Spring的aop

开始学习Spring的aop知识

目标方法:

/**
 * 目标方法类(业务逻辑类)
 */
public class MathCalculator {

    public int div(int i,int j){
        int num = 1/0;
        System.out.println("MathCalculator-------div");
        return i/j;
    }
}

日志切面类

/**
 * 日志切面类
 */
@Aspect
public class LogAspect {



    /**
     * 切入点表达式
     */
    @Pointcut("execution(public int com.myalibaba.aop.MathCalculator.*(..))")
    public void pointCut(){

    }

    @Before("pointCut()")
    public void logStart(JoinPoint point){
        //获取参数
        Object[] args = point.getArgs();
        System.out.println(point.getSignature().getName()+"目标方法运行--->参数列表是"+ Arrays.asList(args));
    }
    @After("com.myalibaba.aop.LogAspect.pointCut()")
    public void logEnd(JoinPoint point){
        System.out.println(point.getSignature().getName()+"目标方法结束---After");
    }

    /**
     * 方法返回值
     * @param result
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void logReturn(JoinPoint point,Object result){
        System.out.println(point.getSignature().getName()+"目标方法正常返回---AfterReturning结果是{}"+result);
    }
    @AfterThrowing(value = "pointCut()",throwing = "exception")
    public void logException(JoinPoint point,Exception exception){
        System.out.println(point.getSignature().getName()+"目标方法异常--->异常信息是{}"+exception.getMessage());
    }
}

配置文件类

@EnableAspectJAutoProxy
@Configuration
public class MainConfigAspect {

    @Bean
    public MathCalculator calculator(){
        return new MathCalculator();
    }

    @Bean
    public LogAspect aspect(){
        return new LogAspect();
    }
}

测试

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigAspect.class);
        MathCalculator calculator = context.getBean(MathCalculator.class);
        calculator.div(1,1);

以上能实现简单的aop切面编程

Aop切面编程(动态代码)

	指的是程序在运行期间动态的将代码切入到指定方法指定位置进行的编码方式

LogAspect 日志切面类

  需要运行到目标方法业务逻辑中

日志切面的方法

   通知方法
   			前置通知---> 在目标方法之前
   			后置通知--->在目标方法运行结束之后
   			返回通知--->在目标方法正常返回
   			异常通知---> 在目标方法出现异常
   			环绕通知--->动态代码推进代码
   将切面类和业务逻辑类需要加入IOC容器管理
   同时需要@Aspect告诉Spring容器哪个类是切面类
   还需要在配置文件类中增加@EnableAspectJAutoProxy

以下来分析为啥加上注解就能实现AOP编程

First

  @EnableAspectJAutoProxy
  @Import({AspectJAutoProxyRegistrar.class})//导入组件
  利用AspectJAutoProxyRegistrar自定义的组件
  internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
  给容器中注册一个AnnotationAwareAspectJAutoProxyCreator的类型

Second

AnnotationAwareAspectJAutoProxyCreator
 AspectJAwareAdvisorAutoProxyCreator
  AbstractAdvisorAutoProxyCreator
   AbstractAutoProxyCreator 实现了两个接口(后置处理器,以及BeanFactoryAware)
   implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
BeanFactoryAware就是获取BeanFactory的工厂   
BeanPostProcessor Bean初始化前后完成的事情

Three

BeanPostProcessor Bean初始化前后完成的事情详细解析
BeanFactoryAware就是获取BeanFactory的工厂 
//debug
public void setBeanFactory(BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
}
后置处理器的逻辑也要打debug

AbstractAdvisorAutoProxyCreator
 public void setBeanFactory(BeanFactory beanFactory) {} 夫类重写了这个方法
      this.initBeanFactory((ConfigurableListableBeanFactory)beanFactory);//方法中调用了这个方法发

AspectJAwareAdvisorAutoProxyCreator
  protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {} 夫类重写这个方法

Four

总结(流程)
1:传入配置类,创建IOC容器
2: 注册配置类,刷新容器
    this.register(annotatedClasses);
    this.refresh(); 
3:this.registerBeanPostProcessors(beanFactory);
    注册Bean的后置处理器方法来拦截Bean的创建     
    1)String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
      先获取IOC容器已经定义好需要创建对象的BeanPostProcessor(只是定义好,还没有创建)
    2)beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    加载一些别的BeanPostProcessor
    3)优先注册实现PriorityOrdered接口的BeanPostProcessor
    4)在注册实现Ordered接口的BeanPostProcessor
    5)注册没有实现优先级接口的BeanPostPrcessor
    6)创建实例在初始化,
         创建Bean的实例   createBeanInstance
         给Bean的属性赋值  populateBean
         initializeBean 初始化Bean(后置处理器就是在这里生效的)
               invokeAwareMethods() 处理Aware接口赋值
               applyBeanPostProcessorsBeforeInitialization() 应用Bean的后置处理器方法
               invokeInitMethods() 执行初始化方法
               applyBeanPostProcessorsAfterInitialization() 应用Bean的后置处理器方法
      7) 把BeanPostProcessor注册到BeanFactory中
      beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
      -----------------以上是创建和注册 AnnotationAwareAspectJAutoProxyCreator 过
 4:完成Bean的finishBeanFactoryInitialization(beanFactory);   方法创建剩下的单实例Bean
        1: 遍历获取容器中所有的Bean,以此创建对象
          getBean()----> doGetBean()--->    this.getSingleton()
        2:创建Bean先从当前缓存中获取
           如果能获取到证明当前Bean是之前创建获取到的,直接使用,否则在创建
           只要创建好的Bean都会被缓存起来
           后置处理器尝试返回对象
            bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                拿到所有的后置处理器,如果是InstantiationAwareBeanPostProcessor就执行			  postProcessBeforeInstantiation方法
       3:createBean()创建Bean的信息
            resolveBeforeInstantiation() 解析,
            希望后置处理器能返回一个代理对象,如果能返回就使用,
            如果不能就继续this.doCreateBean(beanName, mbdToUse, args);   正真的创建Bean实例
5: AnnotationAwareAspectJAutoProxyCreator[InstantiationAwareBeanPostProcessor]    
的作用,
在每一个Bean创建之前,都调用postProcessBeforeInstantiation()方法
关心留意我们自己创建的Bean(MathCalualtor和logAspect)    
   1:判断当前的Bean是否在advisedBeans()中[保存要增强的Bean]
   2:判断当前的Bean是否是基础Bean(Advice,Pointcut,Advisor,AopInfrastructureBean)或者是否是切面
   3:是否需要跳过
        切面里的增强方法
    postProcessAfterInitialization()方法
        this.wrapIfNecessary(bean, beanName, cacheKey);包装如果需要
           Object[] specificInterceptors = t = this.getAdvicesAndAdvisorsForBean(bean.getClass(),
           获取当前Bean的所有增强方法(哪些通知方法是需要切入当前方法的)   
    this.advisedBeans.put(cacheKey, Boolean.TRUE);保存当前增强的Bean
    如果当前Bean需要代理增强,那么就要创建代理对象
    JdkDynamicAopProxy()       
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
//通过Import导入注册类
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值