微信公众号:Java修炼手册
关注可获取3T免费学习资料,助你从0到1;
AOP注解开发
AOP代码实现(执行计算前后输入输出目标代码)
1 定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常)
1 public class MathCalculator {
2 public int div(int i,int j){
3 System.out.println("MathCalculator...div...");
4 return i/j;
5 }
6}
2 定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCalculator.div运行到哪里然后执行;
```java
1@Aspect
2public class LogAspects {
3
4 //抽取公共的切入点表达式
5 //1、本类引用
6 //2、其他的切面引用
7 @Pointcut("execution(public int com.atguigu.aop.MathCalculator.*(..))")
8 public void pointCut(){};
9
10 //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
11 //1使用引入切点方法
12 //joinPoint:用获取方法信息
13 @Before("pointCut()")
14 public void logStart(JoinPoint joinPoint){
15 Object[] args = joinPoint.getArgs();
16 System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+Arrays.asList(args)+"}");
17 }
18 //2使用引用外部切点类的方法
19 @After("com.atguigu.aop.LogAspects.pointCut()")
20 public void logEnd(JoinPoint joinPoint){
21 System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
22 }
23
24 //JoinPoint一定要出现在参数表的第一位
25 @AfterReturning(value="pointCut()",returning="result")
26 public void logReturn(JoinPoint joinPoint,Object result){
27 System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
28 }
29 //joinPoint必须在返回值前面!!
30 @AfterThrowing(value="pointCut()",throwing="exception")
31 public void logException(JoinPoint joinPoint,Exception exception){
32 System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
33 }
34}
通知方法:
@Aspect声明这是一个切面类
前置通知(@Before):logStart:在目标方法(div)运行之前运行
后置通知(@After):logEnd:在目标方法(div)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
3 将切面类和业务逻辑类(目标方法所在类)都加入到容器中;
1@EnableAspectJAutoProxy
2@Configuration
3public class MainConfigOfAOP {
4
5 //业务逻辑类加入容器中
6 @Bean
7 public MathCalculator calculator(){
8 return new MathCalculator();
9 }
10
11 //切面类加入到容器中
12 @Bean
13 public LogAspects logAspects(){
14 return new LogAspects();
15 }
16}
给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】!!!
4 测试
1public class IOCTest_AOP {
2
3 @Test
4 public void test01(){
5 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
6
7 //1、不要自己创建对象
8// MathCalculator mathCalculator = new MathCalculator();
9// mathCalculator.div(1, 1);
10 MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
11
12 mathCalculator.div(1, 0);
13
14 applicationContext.close();
15 }
16
17}
只有在spring容器内的对象才能使用aop功能,所以使用的时候不能自己new一个对象,而是从容器获取!!!
运行结果:
1div运行。。。@Before:参数列表是: {[1, 1]}
2MathCalculator. . .div. . .
3div结束。。。@After
4div正常返回。。。@AfterReturning:运行结果: {1}
执行过程及源码解析
平时看注解的源码有一个小窍门,跟着源码进去会发现,该注解会实现了什么类,或者注入了某些组件,把注入组件的功能,跟注入的时间点搞清楚了,那么该功能的逻辑就会变得清晰
@EnableAspectJAutoProxy是什么?
@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
跟着继承树:
AnnotationAwareAspectJAutoProxyCreator->AnnotationAwareAspectJAutoProxyCreator->AspectJAwareAdvisorAutoProxyCreator->AbstractAdvisorAutoProxyCreator->AbstractAutoProxyCreator
通过他的实现可以发现,它是一个后置处理器,并且也是factoryawrae接口的实现类
AnnotationAwareAspectJAutoProxyCreator注册过程
最后老规矩的总结一下(也相当重要!)
@EnableAspectJAutoProxy 开启AOP功能
@EnableAspectJAutoProxy 会给容器中注册一个组件
AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
容器的创建流程:
registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
finishBeanFactoryInitialization()初始化剩下的单实例bean
组件创建完之后,判断组件是否需要增强
执行目标方法:
代理对象执行目标方法
CglibAopProxy.intercept();
正常的执行顺序:前置通知-》目标方法-》后置通知-》返回通知
出现异常时:前置通知-》目标方法-》后置通知-》异常通知
包括但不限于:分布式架构、高可扩展、高性能、高并发、Jvm性能调优、Spring,MyBatis,Nginx源码分析,Redis,ActiveMQ、Mycat、Netty、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点高级进阶干货面试题集,简历模板等三千多G资料包,关注回复DD无套路免费领取,助您从0到1