最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • Spring如何实现AOP,请不要再说cglib了!

    1. 从注解入手找到对应核心类

    最近工作中我都是基于注解实现 AOP 功能,常用的开启 AOP 的注解是 @EnableAspectJAutoProxy,我们就从它入手。

    上面的动图的流程的步骤就是:

    @EnableAspectJAutoProxy

    <span style=”color: rgb(80, 97, 109); font-size: 15px; font-family: Helvetica, Arial, sans-serif;”–<> AspectJAutoProxyRegistrar

    <span style=”color: rgb(80, 97, 109); font-size: 15px; font-family: Helvetica, Arial, sans-serif;”–<>AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary

    <span style=”color: rgb(80, 97, 109); font-size: 15px; font-family: Helvetica, Arial, sans-serif;”–<>AnnotationAwareAspectJAutoProxyCreator.class

    AnnotationAwareAspectJAutoProxyCreator 查看其中文注释(如下),确定它就是 AOP 的核心类!– 温安适 20191020

    1. AspectJAwareAdvisorAutoProxyCreator的子类 ,用于处理当前应用上下文中的注解切面
    2. 任何被AspectJ注解的类将自动被识别。
    3. 若SpringAOP代理模式可以识别,优先使用Spring代理模式。
    4. 它覆盖了方法执行连接点
    5. 如果使用aop:include元素, 则只有名称与include模式匹配的@aspectj bean才被视为切面 ,并由spring自动代理。
    6. Spring Advisors的处理请查阅,

    org.springframework.aop

    .framework.autoproxy.AbstractAdvisorAutoProxyCreator

    @SuppressWarnings("serial")

    publicclassAnnotationAwareAspectJAutoProxyCreator

    extendsAspectJAwareAdvisorAutoProxyCreator {

    //...省略实现

    }注解切面

    虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

    2. 画核心类类图,猜测核心方法

    AnnotationAwareAspectJAutoProxyCreator 的部分类图。

    AnnotationAwareAspectJAutoProxyCreator

    从类图看到了 AnnotationAwareAspectJAutoProxyCreator 实现了 BeanPostProcessor,而 AOP 功能应该在创建完 Bean 之后执行,猜测 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization(实例化 bean 后处理)是核心方法。查看 AnnotationAwareAspectJAutoProxyCreator 实现的 postProcessAfterInitialization 方法,实际该方法在其父类 AbstractAutoProxyCreator 中。

    //AbstractAutoProxyCreator中的postProcessAfterInitialization实现

    @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,查看其源码如下,发现 createProxy 方法。确定找对了地方。

    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;

    }

    // 创建代理

    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;

    }

    即 AnnotationAwareAspectJAutoProxyCreator 实现 BeanPostProcessor 的 postProcessAfterInitialization 方法,在该方法中由 wrapIfNecessary 实现了 AOP 的功能。wrapIfNecessary 中有 2 个和核心方法

    • getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器
    • createProxy 为当前 bean 创建代理

      要想明白核心流程还需要分析这 2 个方法。

    3. 读重点方法,理核心流程

    3.1 getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器

    查看源码如下,默认实现在 AbstractAdvisorAutoProxyCreator 中。

    @Override

    @Nullable

    protected Object\[\] getAdvicesAndAdvisorsForBean(

    Class<?> beanClass, String beanName,

    @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);

    if (advisors.isEmpty()) {

    return DO\_NOT\_PROXY;

    }

    return advisors.toArray();

    }

    查阅 findEligibleAdvisors 方法,就干了 3 件事

    • 找所有增强器,也就是所有 @Aspect 注解的 Bean
    • 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。
    • 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。

    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {

    //找所有增强器

    List<Advisor> candidateAdvisors = findCandidateAdvisors();

    //找所有匹配的增强器

    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

    extendAdvisors(eligibleAdvisors);

    if (!eligibleAdvisors.isEmpty()) {

    //排序

    eligibleAdvisors = sortAdvisors(eligibleAdvisors);

    }

    return eligibleAdvisors;

    }

    AnnotationAwareAspectJAutoProxyCreator 重写了 findCandidateAdvisors,下面我们看看具体实现了什么

    3.1.1findCandidateAdvisors 找所有增强器,也就是所有 @Aspect 注解的 Bean

    @Override

    protected List<Advisor> findCandidateAdvisors() {

    // Add all the Spring advisors found according to superclass rules.

    List<Advisor> advisors = super.findCandidateAdvisors();

    // Build Advisors for all AspectJ aspects in the bean factory.

    if (this.aspectJAdvisorsBuilder != null) {

    //@Aspect注解的类在这里除了

    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());

    }

    return advisors;

    }

    从该方法我们可以看到处理 @Aspect 注解的 bean 的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。这个方法如下:

    public List<Advisor> buildAspectJAdvisors() {

    List<String> aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {

    synchronized (this) {

    aspectNames = this.aspectBeanNames;

    if (aspectNames == null) {

    List<Advisor> advisors = new ArrayList<>();

    aspectNames = new ArrayList<>();

    //找到所有BeanName

    String\[\] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(

    this.beanFactory, Object.class, true, false);

    for (String beanName : beanNames) {

    if (!isEligibleBean(beanName)) {

    continue;

    }

    // 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。

    Class<?> beanType = this.beanFactory.getType(beanName);

    if (beanType == null) {

    continue;

    }

    if (this.advisorFactory.isAspect(beanType)) {

    //找到所有被@Aspect注解的类

    aspectNames.add(beanName);

    AspectMetadata amd = new AspectMetadata(beanType, beanName);

    if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

    MetadataAwareAspectInstanceFactory factory =

    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

    //解析封装为Advisor返回

    List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

    if (this.beanFactory.isSingleton(beanName)) {

    this.advisorsCache.put(beanName, classAdvisors);

    }

    else {

    this.aspectFactoryCache.put(beanName, factory);

    }

    advisors.addAll(classAdvisors);

    }

    else {

    // Per target or per this.

    if (this.beanFactory.isSingleton(beanName)) {

    thrownew IllegalArgumentException(“Bean with name ‘” + beanName +

    “‘ is a singleton, but aspect instantiation model is not singleton”);

    }

    MetadataAwareAspectInstanceFactory factory =

    new PrototypeAspectInstanceFactory(this.beanFactory, beanName);

    this.aspectFactoryCache.put(beanName, factory);

    advisors.addAll(this.advisorFactory.getAdvisors(factory));

    }

    }

    }

    this.aspectBeanNames = aspectNames;

    return advisors;

    }

    }

    }

    if (aspectNames.isEmpty()) {

    return Collections.emptyList();

    }

    List<Advisor> advisors = new ArrayList<>();

    for (String aspectName : aspectNames) {

    List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);

    if (cachedAdvisors != null) {

    advisors.addAll(cachedAdvisors);

    }

    else {

    MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);

    advisors.addAll(this.advisorFactory.getAdvisors(factory));

    }

    }

    return advisors;

    }

    这个方法可以概括为:

    • 找到所有 BeanName
    • 根据 BeanName 筛选出被 @Aspect 注解的类
    • 针对类中被 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个 Advisor。

    3.2 createProxy 为当前 bean 创建代理。

    3.2.1 创建代理的 2 种方式

    众所周知,创建代理的常用的 2 种方式是:JDK 创建和 CGLIB,下面我们就看看这 2 中创建代理的例子。

    3.2.1 .1 jdk 创建代理的例子

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy;

    publicclassJDKProxyMain {

    publicstaticvoidmain(String\[\] args) {

    JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl();

    // 根据目标对象创建代理对象

    JDKProxyTestInterface proxy =

    (JDKProxyTestInterface) Proxy

    .newProxyInstance(target.getClass().getClassLoader(),

    target.getClass().getInterfaces(),

    new JDKProxyTestInvocationHandler(target));

    // 调用代理对象方法

    proxy.testProxy();

    }

    interfaceJDKProxyTestInterface {

    voidtestProxy();

    }

    staticclassJDKProxyTestInterfaceImpl

    implementsJDKProxyTestInterface {

    @Override

    publicvoidtestProxy() {

    System.out.println(“testProxy”);

    }

    }

    staticclassJDKProxyTestInvocationHandler

    implementsInvocationHandler {

    private Object target;

    publicJDKProxyTestInvocationHandler(Object target){

    this.target=target;

    }

    @Override

    public Object invoke(Object proxy, Method method,

    Object\[\] args)throws Throwable {

    System.out.println(“执行前”);

    Object result= method.invoke(this.target,args);

    System.out.println(“执行后”);

    return result;

    }

    }

    3.2.1 .2 cglib 创建代理的例子

    import org.springframework.cglib.proxy.Enhancer;

    import org.springframework.cglib.proxy.MethodInterceptor;

    import org.springframework.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    publicclassCglibProxyTest {

    staticclassCglibProxyService {

    publicCglibProxyService(){

    }

    voidsayHello(){

    System.out.println(” hello !”);

    }

    }

    staticclassCglibProxyInterceptorimplementsMethodInterceptor{

    @Override

    public Object intercept(Object sub, Method method,

    Object\[\] objects, MethodProxy methodProxy)

    throws Throwable {

    System.out.println(“before hello”);

    Object object = methodProxy.invokeSuper(sub, objects);

    System.out.println(“after hello”);

    return object;

    }

    }

    publicstaticvoidmain(String\[\] args) {

    // 通过CGLIB动态代理获取代理对象的过程

    Enhancer enhancer = new Enhancer();

    // 设置enhancer对象的父类

    enhancer.setSuperclass(CglibProxyService.class);

    // 设置enhancer的回调对象

    enhancer.setCallback(new CglibProxyInterceptor());

    // 创建代理对象

    CglibProxyService proxy= (CglibProxyService)enhancer.create();

    System.out.println(CglibProxyService.class);

    System.out.println(proxy.getClass());

    // 通过代理对象调用目标方法

    proxy.sayHello();

    }

    }

    3.2.1 .3 jdk 创建代理与 cglib 创建代理的区别

    3.2.2 Spring 如何选择的使用哪种方式

    Spring 的选择选择如何代理时在 DefaultAopProxyFactory 中。

    publicclassDefaultAopProxyFactoryimplementsAopProxyFactory,

    Serializable {

    @Override

    public AopProxy createAopProxy(AdvisedSupport config)

    throws AopConfigException {

    if (config.isOptimize()

    || config.isProxyTargetClass()

    || hasNoUserSuppliedProxyInterfaces(config)) {

    Class<?> targetClass = config.getTargetClass();

    if (targetClass == null) {

    thrownew AopConfigException(

    "TargetSource cannot determine target class: "

    +“Either an interface or a target “+

    ” is required for proxy creation.”);

    }

    if (targetClass.isInterface()

    || Proxy.isProxyClass(targetClass)) {

    returnnew JdkDynamicAopProxy(config);

    }

    returnnew ObjenesisCglibAopProxy(config);

    }

    else {

    returnnew JdkDynamicAopProxy(config);

    }

    }

    //...

    }

    • config.isOptimize() 查看源码注释时发现,这个是配置使用 cglib 代理时,是否使用积极策略。这个值一般不建议使用!
    • config.isProxyTargetClass() 就是 @EnableAspectJAutoProxy 中的 proxyTargetClass 属性。

    //exposeProxy=true AopContext 可以访问,proxyTargetClass=true CGLIB 生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

    • hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

    总结下 Spring 如何选择创建代理的方式:

    1. 如果设置了 proxyTargetClass=true,一定是 CGLIB 代理
    2. 如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理
    3. 如果没有实现接口,走 CGLIB 代理

    4. 总结

    Spring 如何实现 AOP?,您可以这样说:

    1. AnnotationAwareAspectJAutoProxyCreator 是 AOP 核心处理类
    2. AnnotationAwareAspectJAutoProxyCreator 实现了 BeanProcessor,其中 postProcessAfterInitialization 是核心方法。
    3. 核心实现分为 2 步

      getAdvicesAndAdvisorsForBean 获取当前 bean 匹配的增强器 createProxy 为当前 bean 创建代理

    4. getAdvicesAndAdvisorsForBean 核心逻辑如下

      a. 找所有增强器,也就是所有 @Aspect 注解的 Bean

      b. 找匹配的增强器,也就是根据 @Before,@After 等注解上的表达式,与当前 bean 进行匹配,暴露匹配上的。

      c. 对匹配的增强器进行扩展和排序,就是按照 @Order 或者 PriorityOrdered 的 getOrder 的数据值进行排序,越小的越靠前。

    5. createProxy 有 2 种创建方法,JDK 代理或 CGLIB

      a. 如果设置了 proxyTargetClass=true,一定是 CGLIB 代理

      b. 如果 proxyTargetClass=false,目标对象实现了接口,走 JDK 代理

      c. 如果没有实现接口,走 CGLIB 代理

    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » Spring如何实现AOP,请不要再说cglib了!

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 211会员总数(位)
    • 3737资源总数(个)
    • 0本周发布(个)
    • 0 今日发布(个)
    • 862稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级