国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Spring AOP 不同配置方式產生的沖突問題

2019-11-15 00:46:19
字體:
來源:轉載
供稿:網友
SPRing AOP 不同配置方式產生的沖突問題

Spring AOP的原理是 JDK 動態代理和CGLIB字節碼增強技術,前者需要被代理類實現相應接口,也只有接口中的方法可以被JDK動態代理技術所處理;后者實際上是生成一個子類,來覆蓋被代理類,那么父類的final方法就不能代理,因為父類的final方法不能被子類所覆蓋。一般而言Spring默認優先使用JDK動態代理技術,只有在被代理類沒有實現接口時,才會選擇使用CGLIB技術來實現AOP。

但是也提供了配置參數來強制選擇使用 CGLIB 技術,如下:

<aop:config proxy-target-class="true" /> 

proxy-target-class="true" 表示強制使用 CGLIB 技術來實現AOP,因為CGLIB是生成子類也就是代理類來實現的,所以proxy-target-class,表示是否代理目標類。<aop:config /> 就會由spring來選擇,spring優先使用JDK動態代理來實現AOP。

<aop:config /> 那么這句配置,會起到什么作用呢?首先它是 aop 命名空間中的配置,所以:

/** * NamespaceHandler for the aop namespace. * @author Rob Harrop * @author Adrian Colyer * @author Juergen Hoeller * @since 2.0 */public class AopNamespaceHandler extends NamespaceHandlerSupport {    /**     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'     * and '{@code scoped-proxy}' tags.     */    @Override    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());    }}

上面的代碼表名,aop命名空間有三個元素:<aop:config />, <aop:aspectj-autoproxy />, <aop:scoped-proxy />,而spring-configured被移到了context命名空間了,也就是變成了: <context:spring-configured />

<aop:config /> 所有的配置,由 ConfigBeanDefinitionParser 來解析:

class ConfigBeanDefinitionParser implements BeanDefinitionParser {    @Override    public BeanDefinition parse(Element element, ParserContext parserContext) {        CompositeComponentDefinition compositeDef =                new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));        parserContext.pushContainingComponent(compositeDef);        configureAutoProxyCreator(parserContext, element); /**  * Configures the auto proxy creator needed to support the BeanDefinitions  * created by the <aop:config/> tag. Will force class proxying if the 'proxy-target-class' attribute is set to 'true'.  * @see AopNamespaceUtils  */ private void configureAutoProxyCreator(ParserContext parserContext, Element element) {  AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element); }

繼續追蹤 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element):

/** * Utility class for handling registration of auto-proxy creators used internally by the 'aop' namespace tags. * Only a single auto-proxy creator can be registered and multiple tags may wish * to register different concrete implementations. As such this class delegates to * AopConfigUtils which wraps a simple escalation protocol. Therefore classes * may request a particular auto-proxy creator and know that class, or a subclass * thereof, will eventually be resident in the application context. * * @author Rob Harrop * @author Juergen Hoeller * @author Mark Fisher * @since 2.0 * @see AopConfigUtils */public abstract class AopNamespaceUtils {    /**     * The  proxy-target-class attribute as found on AOP-related xml tags.     */    public static final String PROXY_TARGET_CLASS_ATTRIBUTE = "proxy-target-class";    /**     * The expose-proxy attribute as found on AOP-related XML tags.     */    private static final String EXPOSE_PROXY_ATTRIBUTE = "expose-proxy";    public static void registerAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {        BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(                parserContext.getRegistry(), parserContext.extractSource(sourceElement));        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);        registerComponentIfNecessary(beanDefinition, parserContext);    }    public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(                parserContext.getRegistry(), parserContext.extractSource(sourceElement));        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);        registerComponentIfNecessary(beanDefinition, parserContext);    }    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(                parserContext.getRegistry(), parserContext.extractSource(sourceElement));        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);        registerComponentIfNecessary(beanDefinition, parserContext);    }

很顯然的這里針對Spring AOP的三種配置方法分別提供了相應的注冊 AutoProxyCreator 的方法:

<aop:config /> 方式對應的注冊AutoProxyCreator 的方法是:registerAspectJAutoProxyCreatorIfNecessary;

<aop:aspectj-autoproxy/> 方式對應的注冊AutoProxyCreator 的方法是:registerAspectJAnnotationAutoProxyCreatorIfNecessary;

DefaultAdvisorAutoProxyCreator 方式對應的注冊AutoProxyCreator 的方法是:registerAutoProxyCreatorIfNecessary;

注:DefaultAdvisorAutoProxyCreator的配置方式一般如下所示:

 <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />

這三個方法最終調用的都是 AopConfigUtils 類同一個方法:

    private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");        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) {                    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;    }

很顯然,AOP的三種方式配置,無論如果是最后在bean factory中是只能存在一個AUTO_PROXY_CREATOR_BEAN的,它的name或者說id就是:

    /**     * The bean name of the internally managed auto-proxy creator.     */    public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";

但是,如果在多個配置文件中,混用了上面所說的AOP的三種配置方法,那么就有可能產生混亂,產生錯誤,比如下面的幾個配置就會報錯:

1>

  <aop:config />       <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />  <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">      <property name="securityManager" ref="securityManager"/>  </bean>

上面采用了 <aop:config /> 來配置 AUTO_PROXY_CREATOR_BEAN,而下面有采用了DefaultAdvisorAutoProxyCreator來配置AUTO_PROXY_CREATOR_BEAN,發布時沒有報錯,但是運行時最終報錯:

java.lang.IllegalStateException: The mapped controller method class 'com.xx.controller.xxController' is not an instance of theactual controller bean instance 'com.sun.proxy.$Proxy45'. If the controller requires proxying (e.g. due to @Transactional),please use class-based proxying.HandlerMethod details: Controller [com.sun.proxy.$Proxy45]Method [public void com.xx.controller.xxController.xxo(xxx)]

2>

如果將上面的 <aop:config /> 改成 <aop:config proxy-target-class="true" /> 也是一樣報相同的錯誤。

3>

但是如果將上面的DefaultAdvisorAutoProxyCreator修改成下面這樣,不管是 <aop:config /> 還是 <aop:config proxy-target-class="true" /> 卻都是可以的。

   <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">       <property name="proxyTargetClass" value="true"/>   </bean>

4>

將 <aop:aspectj-autoproxy /> 與 DefaultAdvisorAutoProxyCreator 配置在一起,哪怕是通過<import resource="" /> 放在一起,都會報錯。

    <aop:aspectj-autoproxy expose-proxy="true"/>     <import resource="../shiro/spring-shiro.xml"/>      <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">        <property name="securityManager" ref="securityManager"/>    </bean>        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">        <property name="proxyTargetClass" value="true"/>    </bean>

報錯信息:

2015-07-06 17:50:02,270 WARN [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'shiroFilter': Requested bean is currently in creation: Is there an unresolvable circular reference?

而將<aop:aspectj-autoproxy /> 與 DefaultAdvisorAutoProxyCreator 分開配置在不同xml文件中,則不存在該問題。

總結

1. Spring AOP有三種配置方式,<aop:config />,<aop:aspectj-autoproxy />, DefaultAdvisorAutoProxyCreator. 如果在一個文件中進行混用,那么就可能會產生錯誤。最好在同一個文件中只采用一種配置方式,推薦使用 <aop:config /> 和 <aop:aspectj-autoproxy />,淘汰DefaultAdvisorAutoProxyCreator的配置方式。

2. Spring的有很多配置都是只在文件級起作用的。

ps:

在VEvb找到一篇類似文章 http://jinnianshilongnian.VEvb.com/blog/1894465


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 台北县| 阿拉善右旗| 盐城市| 大化| 英山县| 盖州市| 浮山县| 潞西市| 泗阳县| 郑州市| 景洪市| 元谋县| 宾阳县| 德钦县| 绥芬河市| 榆树市| 革吉县| 县级市| 华阴市| 平南县| 兴和县| 东莞市| 临夏市| 晋州市| 奉贤区| 宝应县| 临海市| 宾阳县| 乡城县| 自治县| 天长市| 隆德县| 拉孜县| 洛扎县| 齐齐哈尔市| 广元市| 通江县| 甘德县| 明星| 古交市| 香河县|