Spring AOP 代理类,BeanNameAutoProxyCreator cglib
2017-07-28 16:15 Loull 阅读(2082) 评论(0) 收藏 举报BeanNameAutoProxyCreator支持拦截接口和类,但不支持已经被jdk代理过的类$Proxy8。使用cglib才能代理,如下
<!-- 通过bean的名字来匹配选择要代理的bean,在使用时仍用原有bean的id从context中获取 -->  
<bean id="autoProxy"  
    class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
    <!-- 需要代理的service,以userService结尾注册的bean -->  
    <property name="beanNames">  
        <list>  
            <value>*userService</value>  
            <value>*routeService</value>  
        </list>  
    </property>  
    <!-- 拦截器的名称 -->  
    <property name="interceptorNames">  
        <list>  
            <value>validateUserAdvisor</value>  
            <!-- 性能监视增强 -->  
            <value>performanceMonitorAdvice</value>  
        </list>  
    </property>  
    <!-- 设置强制使用CGLIB生成代理,此时代理的bean如果已经是代理则必须也是由cglib生成的 -->  
    <property name="optimize" value="true" />  
</bean>  
optimize是ProxyConfig的属性。意思为 是否对生产代理策略使用优化。
public class ProxyConfig implements Serializable {
    private boolean proxyTargetClass = false;
    private boolean optimize = false;
    boolean opaque = false;
    boolean exposeProxy = false;
    private boolean frozen = false;
}
一个例子
Spring AOP 提供一个可根据Bean名称来自动生产代理的工具,它就是BeanNameAutoProxyCreator。它的配置是这样:
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*impl"></property>  <!-- 只为后缀为"impl"的bean生产代理 -->
        <property name="interceptorNames" value="aServiceAdvisor"></property>   <!-- 一个增强 -->
        <property name="optimize" value="true"></property>   <!-- 是否对代理策略进行优化 -->
    </bean>
以上使用BeanNameAutoProxyCreator 只为后缀为"impl"的Bean生产代理。需要注意的是,这个地方我们不能定义代理接口,也就是interfaces属性,因为我们根本就不知道这些Bean到低实现了多少接口。此时不能代理接口,而只能代理类。所以这里提供了一个新的配置项,它就是optimize。如果为true,则可以对代理生成策略进行优化(默认为false)。也就是说,如果该类有接口,就代理接口(使用JDK代理);如果没有接口,就代理类(使用CGLIB代理)。并非像之前的使用的proxyTargetClass 属性那样,强制代理类,而不去考虑代理接口的方式。
那么就有一个问题了,既然有了CGLIB 可以代理任何类了,那为什么还要JDK的动态代理了?
是因为CGLIB 创建有个特点(创建慢,执行块),然而JDK刚好相反(创建快,执行慢)。如果在运行的时候不断的用CGLIB去创建代理,系统的性能会大打折扣,所以建议一般在系统初始化的使用用CGLIB去创建代理,并放入spring的ApplicationContext中以备后用。
流程分析
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        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.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
ProxyTargetClass (是否强制使用CGLIB来实现代理)
(true : 强制使用CGLIB来实现代理)
(false : 不强制使用CGLIB来实现代理,首选JDK来实现代理)(默认值)
isOptimize (是否对生成代理策略进行优化)
(true : 进行优化,如果有接口就代理接口(使用JDK动态代理),没有接口代理类(CGLIB代理))
(false : 不进行优化) (默认值)

Spring注入bean失败Failed to convert property value of type
Failed to convert property value of type [$Proxy13 
Failed to convert property value of type [$Proxy13] to required type 
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp': no matching editors or conversion strategy found 
Caused by: 
org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessException details (1) are: 
PropertyAccessException 1: 
org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp': no matching editors or conversion strategy found 
Caused by: 
java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp': no matching editors or conversion strategy found 
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:231) 
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:138) 
at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:815) 
当系统出现类似上面的异常信息时,很可能你引用了已经实现了自动代理的Bean,  Cannot convert value of type [$Proxy13] to required type [com.makeprogress.dao.AuthorDaoImp] for property 'authorDaoImp' 提示的意思:你将authorDaoImp注入到一个spring受管Bean中,  但是spring容器提示你注入的Bean类型不对,它说你注入的是 [$Proxy13] 类型,这就说明你可能在无意中将authorDaoImp实现了代理, 此时你再在spring容器中引用 authorDaoImp时得到的将是代理类型。示例如下(在数据源,事务管理器配置完整的前提下): 
http://grey2.iteye.com/blog/994926
A less preferable option is to specify proxy-target-class="true" to your transactional aspect (or whatever makes proxies around your objects)
https://stackoverflow.com/questions/5427077/failed-to-convert-property-value-of-type-proxy1-to-required-type
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号