java代理与Spring AOP

原创
2013/11/24 13:24
阅读数 2.2K

代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。

静态代理类:
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态创建而成。

由此可见,静态代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。  也就是委托模式。

动态代理类
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。  

Spring中的AOP即是代理模式的一种框架级使用

Spring中有使用三种技术实现功能代理;
1.Java动态代理
2.CGlib
3.Aspectj

Spring AOP模式
默认模式
默认Spring使用java动态代理与CGlib混合的代理方式提供服务,即若对象类实现了接口则Spring自动采用java动态代理进行支持,否则采用CGlib进行支持;这中间隐含的是对效率的选择,cglib的效率要略低于java自带动态代理;

当然也可以强制指定使用cglib来进行代理,方法是在xml中配置<aop:aspectj-autoproxy 
proxy-target-class=”true” />进行开启;

使用Spring AOP默认模式的优点是使用简单,不需要LTW(load-time weave)支持,但其缺点是存在自调用方法无法织入的问题(self-invocation issue);

如:类C有方法A,B,
      class C{
        publich void A(){
            System.out.println("A");
            B();
        }

        publich void B(){
            System.out.println("B");
        }
      }
    
若对C类所有方法代理在进入时均输出X
    public X{
        
@Around("execution(* *(..))")

public void logBefore(ProceedingJoinPoint joinPoint) {
            System.out.println("X");
            try {
joinPoint.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
        }
    }
期望其输出结果为
X
A
X
B//即A,B方法均被代理

但结果为
X
A
B//可见A调用同对象方法B时未被代理

该问题产生的根本原因是由于java动态代理与cglib均是采用运行时织入代理方法新生成代理类来,目标类委托给代理类进行处理;
简称代理类为P
调用A方法时调用的其实是P的A方法;
A调用B时,调用的是其目标对象的B方法,即C.B(),而非P.B()
这个问题对于Aspectj模式是不存在的

Aspectj模式

Spring中使用Aspectj是通过LTW修改原类字节码的法来生成代理;

不会生成新的代理类,也就不存在自调用方法无法织入的问题

但其缺点是,程序启动时必须指定javaagent为spring-agent.jar,即-javaagent:D:/spring-agent.jar

另外与默认AOP模式不一样的点在于aop.xml配置文件,默认AOP模式中不需要单独设定AOP文件,其通过<aop:aspectj-autoproxy/> 可自动扫描进行织入;

Aspectj模式中aop.xml默认需要放在META-INF中,Aspectj会扫描所有classpath中的META-INF/aop.xml文件;
某些情况下(比如测试时),我们希望可以指定aop.xml文件的位置,这时可以通过指定java运行参数
-Dorg.aspectj.weaver.loadtime.configuration=test/myaop.xml
但需要注意的是文件位置必须是类路径,不能使用文件系统路径

整合起来启动参数为 -javaagent:D:/spring-agent.jar  -Dorg.aspectj.weaver.loadtime.configuration=test/aop.xml

说的比较苦涩,附件有更详细的代码可以试运行下就明白了 

代码下载:http://vdisk.weibo.com/s/mYJmX

展开阅读全文
打赏
0
18 收藏
分享
加载中
更多评论
打赏
0 评论
18 收藏
0
分享
返回顶部
顶部