开始学习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;
}