`
wuhuajun
  • 浏览: 93869 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SPRING对动态代理的封装

 
阅读更多

spring aop是将系统中业务横切逻辑通过动态代理技术jdk动态代理或者cglib方式织入到指定类指定方法的指定位置上去。

所以springaop其实就是对jdk动态代理和cglib字节码生成技术的一种封装。

 

连接点:针对一个方法  方法调用前 还是调用后 还是异常抛出后 。。

切点:哪些类的哪些方法

增强:横切逻辑

切面:连接点+增强+切点

如果需要spring生成代理类 那么就需要提供切面信息,或者提供增强,连接点 目标对象。

 

封装点一advice:

spring中各种增强接口:其实已经包含了连接点的信息了。

org.springframework.aop.BeforeAdvice

org.springframework.aop.AfterReturningAdvice

org.aopalliance.intercept.MethodInterceptor

org.springframework.aop.ThrowsAdvice

 

ThrowsAdvice的设计比较特别。ThrowsAdvice是标致接口 什么都没有其实什么都有了

规定 方法名afterThrowing 

前三个参数 Method method,Object[] args,Object[] target  要么都有要么没有

Throwable 或者其子类

这样异常抛出的时候 spring就会自动去匹配调用哪个方法了,有点模仿try cache设计 

怎么自动匹配的呢:

最简单就是通过反射获取各个方法异常类型,这样就能确定调用哪个方法了。

还有就是在生成代理对象时候维护个列表信息,这种方法可能性比较大。

 

 

封装点二advisor:提供方便的切点配置

spring提供的切面接口:切面很重要 因为切面包含了连接点+增强+切点所以你如果有了切面的信息那么就能通过spring代理工厂产生代理对象。

1.StaticMethodMatcherPointcutAdvisor       匹配静态方法

2.RegexpmethodpointAdvisor                 用正则表达式匹配

3.DynamicMethodMatcherPointcut 和 DefaultPointcutAdvisor  动态方法意思就是不光具有静态方法匹配  还能进行实际运行时候的值匹配。 运行时候判断实际参数DefaultPointcutAdvisor   里面包含DynamicMethodMatcherPointcut 和advice 这样进行配置 首先会根据静态切点生成代理类 ,具体是否需要加入增强逻辑在允许时候判断动态切点匹配方法是否能匹配上(真实的参数进行判断才能决定是否需要增强 效率低下)。

4.ControlFlowPointCut 和 DefaultPointcutAdvisor     允许时候判断方法堆栈信息。 同上

5.ComposablePointCut 和 DefaultPointcutAdvisor 同上 定义多个PointCut可以取交集

 

生成代理的方式发展

ProxyFactory->ProxyFactoryBean->BeanNameAutoProxyCreator->DefaultAdvisorAutoProxyCreator->AnnotationAwareAspectJAutoProxyCreator(注解方式)

 

ProxyFactory 增强接口实现类 或者直接提供切面接口实现类  必须提供目标对象 。

ProxyFactoryBean 同上 只是这里使用了工厂bean配置文件的方式。 这两种方式很麻烦必须提供目标对象才能获取代理对象。

BeanNameAutoProxyCreator 

DefaultAdvisorAutoProxyCreator

 

比如你配置了<bean id="waiterTarget" class="com.baobaotao.advisor.Waiter" /> 还有切面对象  和 DefaultAdvisorAutoProxyCreator

getBean取到的就已经是代理对象了,spring会在bean生命周期BeanPostProcessor里面作相关的处理 。

 

配置一个Advisor已经包含了切点和增强的信息spring是可以知道哪些需要创建代理对象的,

BeanPostProcessor会干预所有的容器中的bean且能够拦截到bean实例化前实例化后的处理。这样创建代理bean就有可能发生了。

 

同样:

类同于ProxyFactory 用法的有AspectProxyFactory 类 设置个目标对象添加切面就可以生成代理对象了。

AnnotationAwareAspectJAutoProxyCreator(注解方式)  注解扫描 <aop:aspectj-autoproxy />更加简化 基于注解的切面扫描 引入基于Schema的aop命名空间进行配置 属性proxy-target-class 为false 

============================细节======================

jdk动态代理和cglib比对

查看jdk动态代理源码可以看到:获取所有的接口然后通过接口的方法属性生成代理类 在获取代理类的构造函数通过反射的方式创建对象,在代理对象中存在目标对象 每次对目标对象的调用都是通过反射进行调用的。

cglib通过生成子类的方式来实现代理的,所以不能对finally private方法进行代理。 这样cglib生成了子类直接构造子类的实例句柄。执行时候效率高 生成代理类时间长。

总结:jdk方式创建代理对象快  执行对象方法慢 

          cglib方式创建代理对象慢 执行对象方法快 

创建代理对象jdk快10倍左右。

执行cglib快10倍左右。

这样的特点如果是单例 或者对象池化了 那么使用cglib很划算

如果不是单例 那么使用jdk方式比较划算。 

 

 

spring ProxyFactory  对jdk和gblib进行了封装。

 

ProxyFactoryBean几个属性有必要了解下:

interfaces/proxyInterfaces 代理需要实现的接口,可以是多个或者一个

interceptorNames 就是那些增强

singleton 是否单例

optimize 设置为true使用cglib 如果单例最好使用cglib 其他作用域最好使用jdk动态代理

proxyTargetClass 设置填true表示使用cglib 前面的设置存在优先级关系。有了这个忽视了前面设置的接口。

 

 

<!-- 普通方法名匹配切面其他4个类同 -->

<bean id="waiterTarget" class="com.baobaotao.advisor.Waiter" />

<bean id="sellerTarget" class="com.baobaotao.advisor.Seller" />

<bean id="greetingAdvice" class="com.baobaotao.advisor.GreetingBeforeAdvice" />

<bean id="greetingAdvisor" class="com.baobaotao.advisor.GreetingAdvisor"

p:advice-ref="greetingAdvice" />

 

<bean id="parent" abstract="true"

class="org.springframework.aop.framework.ProxyFactoryBean"

p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true" />

<bean id="waiter" parent="parent" p:target-ref="waiterTarget" />

<bean id="seller" parent="parent" p:target-ref="sellerTarget" />

 

public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {

 

public boolean matches(Method method, Class clazz) {

return "greetTo".equals(method.getName());

}

public ClassFilter getClassFilter(){

return new ClassFilter(){

public boolean matches(Class clazz){

return Waiter.class.isAssignableFrom(clazz);

}

};

 

}

}

 

public class GreetingBeforeAdvice implements MethodBeforeAdvice {

public void before(Method method, Object[] args, Object obj) throws Throwable {

String clientName = (String)args[0];

System.out.println(obj.getClass().getName()+"."+method.getName());

System.out.println("How are you!Mr."+clientName+".");

}

}

总结:以上代码是通过ProxyFactoryBean方式获取代理对象其实和DefaultAdvisorAutoProxyCreator大同小异

如果通过spring容器获取一个bean  首先ProxyFactoryBean获取者DefaultAdvisorAutoProxyCreator会查找到你是否配置了advisor如果配置了 查看这个classfilter 是否存在这样的类 如果有 查找methodMatcher

看是否存在匹配的方法 如果有根据advisor里面配置的advice获取到增强 生成代理对象返回给客户端,这就是代理对象的生成过程。

ProxyFactoryBean将逻辑放在工厂方法里面。

DefaultAdvisorAutoProxyCreator放到后处理bean里面。

 

 

 

还有

基于@AspectJ注解方式 <aop:aspectj-autoproxy />这个可以简洁扫描。

基于Schama配置切面如果不能使用jdk5那么就使用这种配置方式了。

eg:

<aop:config>

  <aop:aspect ref="">

     <aop:before pointcut="" method=""/>//这里只要一个类就行 指定方法名

  </aop:aspect >

</aop:config>

或者

 

<aop:config>

  <aop:advisor advice-ref="" pointcut=""/> //这里的advice需要实现增强接口

</aop:config>

 

可以参考spring3.x企业应用开发实战一书第七章  很详细

原理是一样 用法不一样  所以他们可以混用。

 

 

补充:同一对象内的嵌套方法调用拦截失败问题。

无论spring使用的jdk动态代理或者cglib对目标对象进行代理,最后方法调用肯定是在目标对象上的而不是代理对象。

public class TestClass{

           public void testMethod1(){

               

           };

 

           public void testMethod2(){

                testMethod1();

           };

}

 

如果TestClass  testMethod1 testMethod2 两个方法都被aop进行了代理那么在代理对象调用方法testMethod2()时候testMethod2方法确实被代理了 但是testMethod1却没有被代理 ,

 

原因 调用testMethod1其实发生在目标对象的内部并不是在代理对象上,所以如果一定要调用代理后的testMethod1可以这样:((TestClass)AopContext.currentProxy().testMethod1();

这样就没有问题了currentProxy()这个方法也是从Threadlocal中获取到的当前代理对象,由spring进行维护的。

 

分享到:
评论

相关推荐

    spring使用动态代理面向切面编程(AOP) xml

    本篇文章将深入探讨如何使用Spring的动态代理机制实现AOP,以及XML配置的相关知识。 一、面向切面编程(AOP) AOP的核心概念是切面(Aspect)、连接点(Join Point)、通知(Advice)、切入点(Pointcut)和织入...

    Spring-AOP-JDK动态代理

    Spring AOP可以利用JDK动态代理来实现对方法的拦截,当调用目标对象的方法时,实际上执行的是代理对象的方法,从而实现在方法执行前后加入额外逻辑。 以下是使用JDK动态代理实现Spring AOP的步骤: 1. **定义切面...

    spring使用动态代理面向切面编程(AOP) annotation

    本篇文章将深入探讨如何利用Spring的注解来实现AOP,以及其背后的动态代理机制。 首先,了解AOP的基本概念是必要的。AOP的核心是切面(Aspect),它封装了跨越多个对象的行为或关注点。切点(Join Point)是程序...

    在spring中获取代理对象代理的目标对象工具类

    1. **JDK动态代理**:当我们的代理对象是由Spring的JdkDynamicAopProxy创建时,`AopTargetUtils`可以剥离掉代理对象,暴露底层的Java接口实现。 2. **CGLIB代理**:如果目标对象被CGLIB库动态增强,`AopTargetUtils...

    cglib aop spring 动态代理

    2.cglib封装了asm,可以在运行期动态生成新的class。 3.cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。 spring 的AOP功能中 会根据目标类是否实现了接口来判断使用 jdk Proxy还是cglib

    类似spring Aop的Proxy封装

    * 动态代理升级类测试 * @author FANGJINXIN * */ public class ProxyUpTest { public static void main(String[] args) { UserMgr userMgr = new UserMgrImpl(); Object proxy = ProxyUp.newProxy...

    设计模式之动态代理与spring的aop编程

    基于代理的AOP主要使用了我们前面提到的动态代理,它可以对基于接口的类进行代理,而CGLIB库则用于那些没有接口或者需要更底层代理的情况。 Spring AOP中的切面(Aspect)是一个封装了多个相关通知(Advice,即切面...

    spring-aop。以及把代理类 文件输出

    在Java 1.8环境下,Spring AOP支持两种类型的代理:JDK动态代理和CGLIB代理。JDK动态代理适用于实现了接口的类,而CGLIB代理则适用于没有实现接口的类。在本项目中,可能使用了JDK动态代理,因为描述中提到了"需要...

    Spring HttpInvoker的封装

    - **提供工厂方法**:根据配置信息动态创建`HttpInvokerProxyFactoryBean`实例,并返回代理对象。 - **异常处理**:封装异常处理逻辑,比如统一的错误码、错误信息等。 - **超时设置**:根据业务需求设置请求超时...

    Spring AOP的静态代理和动态代理,转移到调用处理器一个集中的方法中处理.docx

    【Spring AOP的静态代理和动态代理】 在软件开发中,代理模式是一种常见的设计模式,它允许我们在不修改原有对象的基础上,对对象的行为进行增强。代理模式的核心思想是通过代理对象来控制对原始对象(也称为委托...

    从JDK动态代理到spring AOP

    本篇将详细探讨JDK动态代理和Spring AOP,以及它们在实际应用中的作用。 首先,JDK动态代理是Java提供的一种在运行时创建代理对象的技术。它允许我们在不修改原有类的基础上,为已有接口添加额外的功能。动态代理的...

    简单模拟spring cglib代理

    Spring支持两种代理机制:基于接口的JDK动态代理和基于类的CGLIB代理。 CGLIB(Code Generation Library)是一个强大的高性能代码生成库,其底层是通过使用操作Java字节码的开源字节码操作框架(比如ASM)来实现的...

    JavaEE spring半自动实现AOP代理

    在Spring中,AOP代理有两种实现方式:JDK动态代理和CGLIB代理。JDK代理适用于实现了接口的类,而CGLIB代理则适用于未实现接口的类。 1. **JDK动态代理**: - Spring通过实现`java.lang.reflect.InvocationHandler`...

    Spring整合JDBC实现转账业务-动态代理模式

    在本示例中,我们将深入探讨如何利用Spring框架与JDBC的整合来实现转账业务,并通过动态代理模式来优化事务管理。动态代理模式是Java中一种强大的设计模式,它允许我们在运行时创建对象的代理,以拦截方法调用并执行...

    动态代理实现AOP机制

    Spring提供了两种AOP代理方式:JDK动态代理和CGLIB。如果目标对象实现了至少一个接口,Spring会选择JDK动态代理;如果没有实现接口,Spring则会使用CGLIB代理。 AOP在Spring中的实现还涉及了切点(Pointcut)、通知...

    动态代理和工厂方法例子

    “006_Dynamic_Proxy_Spring_AOP”文件很可能是关于Spring框架中动态代理的实现,Spring AOP是Spring框架的一部分,它允许我们在不修改源代码的情况下,向现有代码添加新的功能(如日志、事务管理等)。Spring AOP...

Global site tag (gtag.js) - Google Analytics