zoukankan      html  css  js  c++  java
  • AOP动态代理解析1-标签的解析

    spring.handlers

    http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

    public class AopNamespaceHandler extends NamespaceHandlerSupport {
        public void init() {
            // In 2.0 XSD as well as in 2.1 XSD.
            registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
            registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
            registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
            // Only in 2.0 XSD: moved to context namespace as of 2.1
            registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        }
    }

    解析是使用的spirng解析自定义注解的方式,由配置文件得知,在遇到aspectj-autoproxy注解时就会使用解析器AspectJAutoProxyBeanDefinitionParser进行解析,那么看看AspectJAutoProxyBeanDefinitionParse的内部实现。

    注册AnnotationAwareAspectJAutoProxyCreator

        public BeanDefinition parse(Element element, ParserContext parserContext) {
            //注册AnnotationAwareAspectJAutoProxyCreator
         AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); //对注解中子类的处理
         extendBeanDefinition(element, parserContext);
    return null; }

    在registerAspectJAnnotationAutoProxyCreatorIfNeccessary方法中主要完成了3件事情,基本上每行代码都是一个完整的逻辑。

        public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                ParserContext parserContext, Element sourceElement) {
         //注册或升级AutoProxyCreator定义beanName为org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
            BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                    parserContext.getRegistry(), parserContext.extractSource(sourceElement));
            //对于proxy-target-class以及expose-proxy属性的处理
         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); //注册组件并通知,便于监听器进一步处理
         //其中beanDefinition的className为AnnotationAwareAspectJAutoProxyCreator 
         registerComponentIfNecessary(beanDefinition, parserContext); }

    注册或升级AnnotationAwareAspectJAutoProxyCreator

        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
        private static BeanDefinition registerOrEscalateApcAsRequired(Class cls, BeanDefinitionRegistry registry, Object source) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
          //如果已经存在了自动代理创建器且存在的自动代理创建器与现在的不一致那么需要根据优先级来判断到底需要使用哪个
          //org.springframework.aop.config.internalAutoProxyCreator
          if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { //改变bean最重要的就是改变bean所对应的className属性
                apcDefinition.setBeanClassName(cls.getName()); } }
    return null; } 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; }

    以上代码实现了自动注册AnnotationAwareAspectJAutoProxyCreator类的功能,同时这里还涉及了一个优先级的问题,如果已经存在了自动代理创建器,而且存在的自动代理创建器与现在的不一致,那么需要根据优先级来判断到底需要使用哪个。

    处理proxy-target-class以及expose-proxy属性

    useClassProxyingIfNecessary实现了proxy-target-class属性以及expose-proxy属性的处理

        private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
            if (sourceElement != null) {
           //对于proxy-target-class属性的处理  
    boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE)); if (proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); }
           //对于expose-proxy属性的处理 
    boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE)); if (exposeProxy) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }    //强制使用的过程其实也是一个属性设置的过程 public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } }

    proxy-target-class:SpringAOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理(建议尽量使用JDK的动态代理),如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理,所有该目标类型实现的接口都将代理,若该目标对象没有实现任何接口,则创建一个CGLIB代理,如果你希望强制使用CGLIB代理,(例如看望代理目标对象的所有方法,而不只是实现自接口的方法)那也可以。
    但是需要考虑以下两个问题。
    无法通知(advise)Final方法,因为它们不能被重写。
    你需要将CGLIB二进制发行包放在classpath下面。
    JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
    CGLIB:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象时针对目标扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开通的Java字节码编辑类库)操作字节码实现的,性能比JDK强。

    expose-proxy:有时候目标对象内部的自我调用将无法实施切面中的增强,this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强,因此b方法的事务定义“@Transactional(propagation = Propagation.REQUIRES_NEW)”将不会实施,为了解决这个问题,将以上代码中的“this.b();”修改为“((AService) AopContext.currentProxy()).b();”即可。通过以上的修改便可以完成对a和b方法的同时增强。

    最后注册组件并通知,便于监听器做进一步处理

        private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
            if (beanDefinition != null) {
           //org.springframework.aop.config.internalAutoProxyCreator BeanComponentDefinition componentDefinition
    = new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME); parserContext.registerComponent(componentDefinition); } }
  • 相关阅读:
    冒泡排序
    【代码审计】appcms 文件包含漏洞
    【知识学习】PHP实现批量替换字典后缀
    【代码学习】PYTHON 列表循环遍历及列表常见操作
    【代码学习】PYTHON字符串的常见操作
    【知识学习】Sublime Text 快捷键精华版
    【代码审计】变量覆盖漏洞详解
    【渗透测试】Msf提权步骤
    【代码审计】VAuditDemo 前台搜索功能反射型XSS
    【代码审计】VAuditDemo 前台搜索注入
  • 原文地址:https://www.cnblogs.com/wade-luffy/p/6076694.html
Copyright © 2011-2022 走看看