Spring-AOP分析

AOP都知道,是spring中的面向切面编程,就是可以把我们写的代码横向扩展,而且又不会影响原来的代码结构,是一种思想。说白了就是可以在你想实现什么功能的前后能够搞一些事情。底层使用的是JDK和Cglib动态代理

为什么要使用AOP呢:
1、AOP采用了横向的抽取机制,取代了传统纵向继承体系重复性代码结构
2、可以在不修改源代码的前提下,对程序功能进行增强

主要的几种的方式:
1、前置通知:@Before 在我们执行目标方法前运行
2、后置通知:@After 在我们目标方法运行之后运行,不管有没有异常
3、后置返回通知:@AfterReturning 在我们的目标方法正常返回值之后运行
4、异常通知:@AfterThrowing 在我们执行目标方法出现异常之后运行
5、环绕通知:@Around 前置 > @Before +后置 < @After(正常) 动态代理,必须手动执行目标方法

注解实现AOP

先创建一个Service和接口类

public interface UserService {
    public String selectUserName();
}
@Service("userService")
public class UserServiceImp implements UserService {
    @Override
    public String selectUserName() {
        String name = "zx";
        return name;
    }
}

创建实体类

public class UserEntity {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

创建一个控制层

@RestController
@RequestMapping("/aop")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/aoptest")
    public void UserTest(){
        System.out.println("UserServiceImp方法");
        userService.selectUserName();
    }
}

创建代理的配置类。把bean注入到容器中

@Configuration
@EnableAspectJAutoProxy
public class UserConfig{
        /**
         * 把目标类注册到spring容器中去
         * @return
         */
        @Bean
        public UserService userService(){
            return new UserService() {
                @Override
                public String selectUserName() {
                    String name = "配置类实例";
                    return name;
                }
            };
        }

        /**
         * 注册切面类到spring容器中去
         * @return
         */
        @Bean
        public UserPointCut servantAspects02(){
            return new UserPointCut();
        }
}

再创建一个切面类

@Aspect
@Component
public class UserPointCut {
    @Pointcut("execution(* com.zx.springaop.service..*(..))")
    public void UserPointCut(){}

    @Before("UserPointCut()")
    public void BeforUser(){
        System.out.println("前置");
    }

    @After("UserPointCut()")
    public void AfterUser(){
        System.out.println("后置");
    }

    @AfterReturning("UserPointCut()")
    public void AfterReturning(){
        System.out.println("后置返回");
    }
    @AfterThrowing(value = "UserPointCut()",throwing = "ex")
    public void AfterThreadExction(Exception ex){
        System.out.println("后置异常抛出"+ex);
    }

    @Around("UserPointCut()")
    public Object AroudUserCut(ProceedingJoinPoint pjd)  {
        Object result=null;
        String methodName=pjd.getSignature().getName();//方法名
        try {
            //前置通知
            System.out.println("the method "+methodName+" begins with "+Arrays.asList(pjd.getArgs()));
            result=pjd.proceed();
            //结果通知
            System.out.println("the method"+methodName+" ends "+result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("the method "+methodName+" occurs execption:"+e);
            throw new RuntimeException(e);
        }
        //后置通知
        System.out.println("the method "+methodName+" ends");
        return result;
    }
}

最后创建一个测试类

public class UserPointCutTest {
    public static void main(String args[]){
        AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(UserConfig.class);
        UserService userService = (UserService) acc.getBean(UserService.class);
        userService.selectUserName();
    }
}

输出:
在这里插入图片描述
——————————————————————————————
下面开始分析。
所谓的jdk动态代理或者是CGLib动态代理完全取决于
打断点,看debug模式,

可以看到现在是JDK的动态代理模式,那么怎么可以转变成CGLib呢,
在这里插入图片描述
状态改为true就是强制使用CGLib动态代理了。说白了就是把有没有接口。有接口就是JDK,没有就默认CGLib
在这里插入图片描述
流程分析:

将bean导入spring容器AspectJAutoProxyRegistrar->ImportBeanDefinitionRegistrar#registerBeanDefinitions

将bean注册到spring容器 AnnotationAwareAspectJAutoProxyCreator className: org.springframework.aop.config.internalAutoProxyCreator class: 根据spring提供的规范构建spring bean RootBeanDefinition

上面构建 AnnotationAwareAspectJAutoProxyCreator 这个bean 然后这个bean实现InstantiationAwareBeanPostProcessor接口
该接口实现BeanPostProcessor接口 BeanPostProcessor是spring提供的扩展接口 在bean实例的时候回调 --》postProcessAfterInitialization

然后就会找所有的Advisor
1、 第一步: 先找父类时候有实现Advisor的接口。
2、 第二步: 然后找到所有类上面注解标注为@Aspect, 然后解析该类标注Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

AOP的 实现方式很简单,就是动态代理。就是在实例化的时候生成代理类,来替换掉真实实现类来对外提供服务。就是在getBean(…)的时候返回的其实是代理类的一个实例,而这个代理类就是JDK活着CGLib动态生成的,(spring-aop只能在Spring中才能实现。)

先看一下 DefaultAdvisorAutoProxyCreator类中的BeanPostProcessor方法。在IOC中,这个方法是在init-method前后执行的。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

回顾一下IOC:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {
 
    // Instantiate the bean.
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 1. 创建实例
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    ...
 
    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
        // 2. 装载属性
        populateBean(beanName, mbd, instanceWrapper);
        if (exposedObject != null) {
            // 3. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    }
    ...
}

在第三步,初始化Bean,会调用BeanPostProcessor()方法

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   ...
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 1. 执行每一个 BeanPostProcessor 的 postProcessBeforeInitialization 方法
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
 
   try {
      // 调用 bean 配置中的 init-method="xxx"
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   ...
   if (mbd == null || !mbd.isSynthetic()) {
      // 我们关注的重点是这里!!!
      // 2. 执行每一个 BeanPostProcessor 的 postProcessAfterInitialization 方法
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

也就是说,Spring AOP 会在 IOC 容器创建 bean 实例的最后对 bean 进行处理。其实就是在这一步进行代理增强。

DefaultAdvisorAutoProxyCreator 的继承结构中,postProcessAfterInitialization() 方法在其父类 AbstractAutoProxyCreator 这一层被覆写了:

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (!this.earlyProxyReferences.contains(cacheKey)) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

看wrapifnecessary方法。会返回一个代理类


protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }
 
   // 返回匹配当前 bean 的所有的 advisor、advice、interceptor
   // 对于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 这两个 bean 创建过程中,
   //   到这边的时候都会返回两个 advisor
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 创建代理...创建代理...创建代理...
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }
 
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

在看 createProxy(…)方法,创建代理类:


// 注意看这个方法的几个参数,
//   第三个参数携带了所有的 advisors
//   第四个参数 targetSource 携带了真实实现的信息
protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }
 
   // 创建 ProxyFactory 实例
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);
 
   // 在 schema-based 的配置方式中,我们介绍过,如果希望使用 CGLIB 来代理接口,可以配置
   // proxy-target-class="true",这样不管有没有接口,都使用 CGLIB 来生成代理:
   //   <aop:config proxy-target-class="true">......</aop:config>
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 点进去稍微看一下代码就知道了,主要就两句:
         // 1. 有接口的,调用一次或多次:proxyFactory.addInterface(ifc);
         // 2. 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
 
   // 这个方法会返回匹配了当前 bean 的 advisors 数组
   // 对于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到这边的时候都会返回两个 advisor
   // 注意:如果 specificInterceptors 中有 advice 和 interceptor,它们也会被包装成 advisor,进去看下源码就清楚了
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }
 
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
 
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
 
   return proxyFactory.getProxy(getProxyClassLoader());
}

这个方法主要是在内部创建了一个 ProxyFactory 的实例,然后 set 了一大堆内容,剩下的工作就都是这个 ProxyFactory 实例的了,通过这个实例来创建代理: getProxy(classLoader)。

看看代理类

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

通过创建代理类来生成aop代理

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}

创建 AopProxy 之前,我们需要一个 AopProxyFactory 实例,然后看 ProxyCreatorSupport 的构造方法:

public ProxyCreatorSupport() {
   this.aopProxyFactory = new DefaultAopProxyFactory();
}

看DefaultAopProxyFactory 这个类,我们看它的 createAopProxy(…) 方法:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
 
   @Override
   public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
      // (我也没用过这个optimize,默认false) || (proxy-target-class=true) || (没有接口)
      if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
         Class<?> targetClass = config.getTargetClass();
         if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                  "Either an interface or a target is required for proxy creation.");
         }
         // 如果要代理的类本身就是接口,也会用 JDK 动态代理
         // 我也没用过这个。。。
         if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
         }
         return new ObjenesisCglibAopProxy(config);
      }
      else {
         // 如果有接口,会跑到这个分支
         return new JdkDynamicAopProxy(config);
      }
   }
   // 判断是否有实现自定义的接口
   private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
      Class<?>[] ifcs = config.getProxiedInterfaces();
      return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
   }
 
}

这就有可能返回jdk,也有可能返回cglib,然后下面就分别是jdk和cglib的源码,最后各自集成各自的拦截类,进行代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值