IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring-AOP配置(注解及多方整合案例) -> 正文阅读

[Java知识库]Spring-AOP配置(注解及多方整合案例)

目录

注解配置AOP

注解开发AOP制作步骤

注解开发AOP注意事项

小记

实例演示

注解AOP通知执行顺序控制

AOP注解驱动

实例演示

注解多方整合案例

案例介绍

案例分析

案例制作步骤

案例后续思考与设计

实例演示


  • 注解配置AOP

  • 注解开发AOP制作步骤

  • 在XML格式基础上
  • 导入坐标(伴随spring-context坐标导入已经依赖导入完成)
  • 开启AOP注解支持
  • 配置切面@Aspect
  • 定义专用的切入点方法,并配置切入点@Pointcut
  • 为通知方法配置通知类型及对应切入点如@Before
  • 注解开发AOP注意事项

  • 1.切入点最终体现为一个方法,无参无返回值,无实际方法体内容,但不能是抽象方法
  • 2.引用切入点时必须使用方法调用名称,方法后面的()不能省略
  • 3.切面类中定义的切入点只能在当前类中使用,如果想引用其他类中定义的切入点要使用“类名.方法名()”引用
  • 4.可以在通知类型注解后添加参数,实现XML配置中的属性,例如after-returning后的returning属性
  • 小记

  • 名称:@Aspect
  • 类型:注解
  • 位置:类定义上方
  • 作用:设置当前类为切面类
  • 格式:
  • @Aspect
  • public class AopAdvice{}
  • 说明:一个beans标签中可以配置多个aop:config标签
  • 名称:@Pointcut
  • 类型:注解
  • 位置:方法定义上方
  • 作用:使用当前方法名作为切入点引用名称
  • 格式:
  • @Pointcut("execution(* *(..))")
  • public void pt(){}
  • 说明:被修饰的方法忽略其业务功能,格式设定为无参无返回值的方法,方法体内空实现(非抽象)
  • 名称:@Before
  • 类型:注解
  • 位置:方法定义上方
  • 作用:标注当前方法作为前置通知
  • 格式:
  • @Before("pt()")
  • public void before(){}
  • 特殊参数:
  • 名称:@After
  • 类型:注解
  • 位置:方法定义上方
  • 作用:标注当前方法作为后置通知
  • 格式:
  • @After("pt()")
  • public void after(){}
  • 特殊参数:
  • 名称:@AfterReturning
  • 类型:注解
  • 位置:方法定义上方
  • 作用:标注当前方法作为返回后通知
  • 格式:
  • @AfterReturning(value="pt()",returning="ret")
  • public void afterReturning(Object ret) {}
  • 特殊参数:
  • returning:设定使用通知方法参数接收返回值的变量名
  • 名称:@AfterThrowing
  • 类型:注解
  • 位置:方法定义上方
  • 作用:标注当前方法作为异常后通知
  • 格式:
  • @AfterThrowing(value="pt()",throwing="t")
  • public void afterThrowing(Throwable t){}
  • 特殊参数:
  • throwing:设定使用通知方法参数接收原始方法中抛出的异常对象名
  • 名称:@Around
  • 类型:注解
  • 位置:方法定义上方
  • 作用:标注当前方法作为环绕通知
  • 格式:
  • @Around("pt()")
  • public Object around(ProceedingJoinPoint pjp) throws Throwable{Object ret=pjp.proceed();
  • return ret;}
  • 特殊参数:
  • 实例演示

  • <!--SSS2.开启磁盘扫描-->
        <context:component-scan base-package="com.superdemo"/>
        <!--SSS1.开启aop注解支持-->
        <aop:aspectj-autoproxy/>
    
    
        <!--<bean id="userService" class="com.superdemo.service.impl.UserServiceImpl"/>-->
        <!--2.配置共性功能成为spring控制的资源-->
        <!--<bean id="myAdvice" class="com.superdemo.aop.AOPAdvice"/>-->
        <!--4.配置AOP-->
        <!--<aop:config>
            5.配置切入点
            <aop:pointcut id="pt" expression="execution(* *..*(..))"/>
            6.配置切面(切入点与通知的关系)
            <aop:aspect ref="myAdvice">
                7.配置具体的切入点对应通知中的哪个操作方法
                <aop:before method="before" pointcut-ref="pt"/>
                <aop:after method="after" pointcut-ref="pt"/>
                <aop:after-returning method="afterReturing" pointcut-ref="pt" returning="ret"/>
                <aop:after-throwing method="afterThrowing" pointcut-ref="pt" throwing="t"/>
                <aop:around method="around" pointcut-ref="pt"/>
            </aop:aspect>
        </aop:config>-->
  • @Service("userService")
    public class UserServiceImpl implements UserService {
        public void save(int i){
            //0.将共性功能抽取出来
            //System.out.println("共性功能");
            System.out.println("user service running..."+i);
            //int i=1/0;
        }
    
        @Override
        public int update(int a,int b) {
            System.out.println("user service update running...");
            return a+b;
        }
    
        @Override
        public void delete() {
            System.out.println("user service delete running...");
            int i = 1/0;
        }
    }
  • public class AOPPointcut {
        @Pointcut("execution(* *..*(..))")
        public void pt1(){}
    }
  • //1.制作通知类,在类中定义一个方法用于完成共性功能
    @Component
    @Aspect
    public class AOPAdvice {
    
        //@Pointcut("execution(* *..*(..))")
        //public void pt(){}
    
        @Before("AOPPointcut.pt1()")
        public void before(JoinPoint jp){
            Object[] args = jp.getArgs();
            System.out.println("前置before..."+args[0]);
        }
    
        @After("AOPPointcut.pt1()")
        public void after(JoinPoint jp){
            Object[] args = jp.getArgs();
            System.out.println("后置after..."+args[0]);
        }
    
        @AfterReturning(value = "AOPPointcut.pt1()",returning = "ret")
        public void afterReturing(Object ret){
            System.out.println("返回后afterReturing..."+ret);
        }
    
        @AfterThrowing(value = "AOPPointcut.pt1()",throwing = "t")
        public void afterThrowing(Throwable t){
            System.out.println("抛出异常后afterThrowing..."+t.getMessage());
        }
    
        @Around("AOPPointcut.pt1()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前around before...");
            //对原始方法的调用
            /*Object ret = null;
            try {
                ret = pjp.proceed();
            } catch (Throwable e) {
                System.out.println("around...exception..."+e.getMessage());
            }*/
            Object ret = pjp.proceed();
            System.out.println("环绕后around after...");
            return ret;
        }
    }
  • public class App {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) ctx.getBean("userService");
            //userService.save(666);
            int tj = userService.update(666,123);
            System.out.println("执行结果...."+tj);
            //userService.delete();
        }
    }
  • 注解AOP通知执行顺序控制

  • AOP使用XML配置情况下,通知的执行顺序由配置顺序决定
  • 在注解情况下由于不存在配置顺序的概念的概念,参照通知所配置的方法名字符串对应的编码值顺序,可以简单理解为字母排序
  • 同一个通知类中,相同通知类型以方法名排序为准
  • 不同通知类中,以类名排序为准
  • 使用@Order注解通过变更bean的加载顺序改变通知的加载顺序
  • 企业开发经验
  • 通知方法名由3部分组成,分别是前缀、顺序编码、功能描述
  • 前缀为固定字符串,例如baidu、Swisse等,无实际意义
  • 顺序编码为6位以内的整数,通常3位即可,不足位补0
  • 功能描述为该方法对应的实际通知功能,例如exception、strLenCheck
  • 控制通知执行顺序使用顺序编码控制,使用时做一定空间预留
    • 003使用,006使用,预留001、002、004、005、007、008
    • 使用时从中段开始使用,方便后期做前置追加或后置追加
    • 最终顺序以运行顺序为准,以测试结果为准,不以设定规则为准
  • AOP注解驱动

  • 名称:@EnableAspectJAutoProxy
  • 类型:注解
  • 位置:Spring注解配置类定义上方
  • 作用:设置当前类开启AOP注解驱动的支持,加载AOP注解
  • 格式:
  • @Configuration
  • @ComponentScan("com.superdemo")
  • @EnableAspectJAutoProxy
  • public class SpringConfig{}
  • 实例演示

  • @Configuration
    @ComponentScan("com.superdemo")
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }
  • @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class UserServiceTest {
        @Autowired
        private UserService userService;
    
        @Test
        public void testupdate(){
            int ret = userService.update(666, 123);
            Assert.assertEquals(789,ret);
        }
    }
  • 注解多方整合案例

  • 案例介绍

  • 对项目进行业务层接口执行监控,测量业务层接口的执行效率
  • 案例分析

  • 测量接口执行效率:接口方法执行前后获取执行时间,求出执行时长
    • System.currentTimeMillis()
  • 对项目进行监控:项目中所有接口方法,AOP思想,执行期动态织入代码
    • 环绕通知
    • proceed()方法执行前后获取系统时间
  • 案例制作步骤

  • 定义切入点(务必要绑定到接口上,而不是接口实现类上)
  • 制作AOP环绕通知,完成测量功能
  • 注解配置AOP
  • 开启注解驱动支持
  • 案例后续思考与设计

  • 测量真实性
    • 开发测量是隔离性反复执行某个操作,是理想情况,上线测量差异过大
    • 上线测量服务器性能略低于单机开发测量
    • 上线测量基于缓存的性能查询要优于数据库查询测量
    • 上线测量接口的性能与最终对外提供的服务性能差异过大
    • 当外部条件发生变化(硬件),需要进行回归测试,例如数据库迁移
  • 测量结果展示
    • 测量结果无需每一个都展示,需要设定检测阈值
    • 阈值设定要根据业务进行区分,一个复杂的查询与简单的查询差异化很大
    • 阈值设定需要做独立的配置文件或通过图形工具配置(工具级别的开发)
    • 配合图形界面展示测量结果
  • 实例演示

  • src下domain层
  • public class Account {
        private Integer id;
        private String name;
        private Double money;
    
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Double getMoney() {
            return money;
        }
        public void setMoney(Double money) {
            this.money = money;
        }
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", money=" + money +
                    '}';
        }
    }
  • src下dao层
  • public interface AccountDao {
        @Insert("INSERT INTO account(name, money) VALUES (#{name},#{money})")
        void save(Account account);
    
        @Delete("DELETE FROM account WHERE id = ${id}")
        void delete(Integer id);
    
        @Update("UPDATE account SET name = #{name},money = #{money} WHERE id = #{id}")
        void update(Account account);
    
        @Select("SELECT * FROM account")
        List<Account> findAll();
    
        @Select("SELECT * FROM account WHERE id = #{id}")
        Account findByid(Integer id);
    }
  • src下service层
  • public interface AccountService {
        void save(Account account);
    
        void delete(Integer id);
    
        void update(Account account);
    
        List<Account> findAll();
    
        Account findByid(Integer id);
    }
  • @Service("accountService")
    public class AccountServiceImpl  implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
        /*public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }*/
    
        public void save(Account account){
            accountDao.save(account);
        }
    
        public void delete(Integer id){
            accountDao.delete(id);
        }
    
        public void update(Account account){
            accountDao.update(account);
        }
    
        public List<Account> findAll(){
            return accountDao.findAll();
        }
    
        public Account findByid(Integer id){
            return accountDao.findByid(id);
        }
    }
  • src下resources
  • jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/dp1?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    jdbc.username=root
    jdbc.password=109923
  • src下aop
  • @Component
    @Aspect
    public class RunTimeMonitorAdvice {
        //切入点,监控业务层接口
        @Pointcut("execution(* com.superdemo.service.*Service.find*(..))")
        public void pt(){}
    
        @Around("pt()")
        public Object runtimeAround(ProceedingJoinPoint pjp) throws Throwable {
            Signature signature = pjp.getSignature();
            String className = signature.getDeclaringTypeName();
            String methodName = signature.getName();
    
            Object ret = null;
            long sum = 0L;
    
            for(int i = 0; i < 10000; i++){
                long startTime = System.currentTimeMillis();
                ret= pjp.proceed();
                long endTime = System.currentTimeMillis();
                sum += endTime-startTime;
            }
    
            System.out.println(className+":"+methodName+":万次运行了:"+sum+"ms");
    
            return ret;
        }
    }
  • src下config层
  • public class JDBCConfig {
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String userName;
        @Value("${jdbc.password}")
        private String password;
    
        @Bean("dataSource")
        public DataSource getDataSource(){
            DruidDataSource ds = new DruidDataSource();
            ds.setDriverClassName(driver);
            ds.setUrl(url);
            ds.setUsername(userName);
            ds.setPassword(password);
            return ds;
        }
    }
  • public class MybatisConfig {
        /*
            对应XML格式下:
        spring整合mybatis后控制的创建连接用的对象
        <bean  class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="typeAliasesPackage" value="com.superdemo.domain"/>
        </bean>
        加载mybatis映射配置的扫描,将其作为spring的bean进行管理
        <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.superdemo.dao"/>
        </bean>*/
    
        @Bean
        public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
            SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
            ssfb.setTypeAliasesPackage("com.superdemo.domain");
            ssfb.setDataSource(dataSource);
            return ssfb;
        }
    
        @Bean
        public MapperScannerConfigurer getMapperScannerConfigurer(){
            MapperScannerConfigurer msc = new MapperScannerConfigurer();
            msc.setBasePackage("com.superdemo.dao");
            return msc;
        }
    }
  • @Configuration
    @ComponentScan("com.superdemo")
    @PropertySource("classpath:jdbc.properties")
    @Import({JDBCConfig.class, MybatisConfig.class})
    @EnableAspectJAutoProxy
    public class SpringConfig {
    }
  • test下测试
  • //设定spring专用的类加载器
    @RunWith(SpringJUnit4ClassRunner.class)
    //设定加载的spring上下文对应的配置
    @ContextConfiguration(classes = SpringConfig.class)
    public class UserServiceTest {
        @Autowired
        private AccountService accountService;
    
        @Test
        public void testFindById(){
            Account ac = accountService.findByid(2);
            System.out.println(ac);
        }
    
        @Test
        public void testFindAll(){
            List<Account> list = accountService.findAll();
            Assert.assertEquals(3,list.size());
        }
    }
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:12:55  更:2022-09-21 00:17:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:57:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码