德云社论字排辈?和AOP好像哦(一)

一:AOP

1.1)AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

1.2)基本概念

AOP核心概念
1、横切关注点(对哪些方法进行切入)
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect,把原来糅杂在业务逻辑代码中的非业务代码抽取出来,把功能相同的放在一个类中形成一个切面)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)(需要切入的点)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

1.3)简单案例:

接口

 1 public interface Calculate {
 2  /** * 加法 * @param numA * @param numB * @return */
 3     int add(int numA,int numB); 
 4 /** * 减法 * @param numA * @param numB * @return */
 5     int reduce(int numA,int numB);
 6  /** * 除法 * @param numA * @param numB * @return */
 7     int div(int numA,int numB); 
 8 /** * 乘法 * @param numA * @param numB * @return */
 9     int multi(int numA,int numB); 
10 }
View Code
实现类
1 public class ZhangjiangCalculate implements Calculate { 
2     public int add(int numA, int numB) { return numA+numB; }
3     public int reduce(int numA, int numB) { return numA-numB; }                public int div(int numA, int numB) { return numA/numB; }    
4     public int multi(int numA, int numB) { return numA*numB; } }    
View Code
切面类
 1 @Aspect
 2 public class ZhangjiangLogAspect {
 3     @Pointcut("execution(* com.zhangjiang.ZhangjiangCalculate.*(..))")
 4     public void pointCut(){};
 5     @Before(value = "pointCut()")
 6     public void methodBefore(JoinPoint joinPoint){
 7         String methodName = joinPoint.getSignature().getName();
 8         System.out.println("执行目标方法【"+methodName+"】之前执行<前置通知>,入参"+ Arrays.asList(joinPoint.getArgs()));
 9     }
10 
11     @After(value = "pointCut()")
12     public void methodAfter(JoinPoint joinPoint) {
13         String methodName = joinPoint.getSignature().getName();
14         System.out.println("执行目标方法【"+methodName+"】之前执行<后置通知>,入参"+Arrays.asList(joinPoint.getArgs()));
15     }
16 
17     @AfterReturning(value = "pointCut()")
18     public void methodReturning(JoinPoint joinPoint ) {
19         String methodName = joinPoint.getSignature().getName();
20         System.out.println("执行目标方法【"+methodName+"】之前执行<返回通知>,入参"+Arrays.asList(joinPoint.getArgs()));
21     }
22 
23     @AfterThrowing(value = "pointCut()")
24     public void methodAfterThrowing(JoinPoint joinPoint) {
25         String methodName = joinPoint.getSignature().getName();
26         System.out.println("执行目标方法【"+methodName+"】之前执行<异常通知>,入参"+Arrays.asList(joinPoint.getArgs()));
27     }
28 }
View Code
配置类
 1 @Configuration 
 2 @EnableAspectJAutoProxy 
 3 public class MainConfig { 
 4     @Bean 
 5     public Calculate calculate() { 
 6         return new ZhangjiangCalculate(); 
 7     }
 8     @Bean 
 9     public ZhanjiangLogAspect zhangjiangLogAspect() { 
10         return new ZhangjiangLogAspect(); 
11     } 
12 }
View Code

2)我们看到在我们配置类上加入了@EnableAspectJAutoProxy这个东东?我们着重来分析一下这个东东给我容器中添加了什么组件?

2.1)我们发现@EnableAspectJAutoProxy上标注了一个@Import注解,我们知道@Import可以给我们容器中添加组件

1 @Target(ElementType.TYPE) 
2 @Retention(RetentionPolicy.RUNTIME) 
3 @Documented 
4 @Import(AspectJAutoProxyRegistrar.class) 
5 public @interface EnableAspectJAutoProxy {
View Code

2.2)所有我们来分析AspectJAutoProxyRegistrar类是用来干什么的?

经过跟踪源代码我们发现,AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,凡是实现了ImportBeanDefinitionRegistrar可以给我们容器中添加bean定义信息
作用:往容器中注册了一个名称叫org.springframework.aop.config.internalAutoProxyCreator类型为AnnotationAwareAspectJAutoProxyCreator 注解的apsectj自动代理创建器
AspectJAutoProxyRegistrar源码
 1 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { 
 2     @Override 
 3     public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
 4     //往容器中注册对应的 aspectj注解自动代理创建器     
 5 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 
 6 
 7     AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); 
 8 
 9     if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {     AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);         
10     }
11 
12     if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {          AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); 
13     } 
14 } 
View Code

进入AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

 1 public static BeanDefinition     
 2 registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { 
 3     return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null); 
 4 }
 5 
 6 //注册一个AnnotationAwareAspectJAutoProxyCreator(注解适配的切面自动创建器) 
 7 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { 
 8     return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); 
 9 }
10 
11 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {     
12      Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); 
13 
14 //判断容器中有没有org.springframework.aop.config.internalAutoProxyCreator 名称的bean定义 
15 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { 
16     BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); 
17     if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
18     int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
19      int requiredPriority = findPriorityForClass(cls); 
20             if (currentPriority < requiredPriority) {         
21                  apcDefinition.setBeanClassName(cls.getName()); 
22             } 
23     }
24     return null; 
25 } 
26 
27 //容器中没有 那么就注册一个名称叫org.springframework.aop.config.internalAutoProxyCreator 类型是AnnotationAwareAspectJAutoProxyCreator的bean定义 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; 
28 }  
View Code

 

posted @ 2020-10-19 23:03  powerZhangFly  阅读(198)  评论(0)    收藏  举报