aop 代理类往被代理泪怎么spring aop 传参数数

基于Java Dynamic Proxy(面向Interface)的Spring AOP实现原理 - 茂盛博客 - ITeye技术网站
博客分类:
Dynamic Proxy是面向接口的动态代理实现,其代理对象必须是某个接口的实现。Dynamic Proxy通过在运行期构建一个此接口的动态实现类完成对目标对象的代理(相当于在运行期动态构造一个UserDAOProxy,完成对UserDAOImp的代理任务)。而如果目标代理对象并未实现任何接口,那么Dynamic Proxy就失去了创建动态代理类的基础依据。
我们先来看传统方式下一个Proxy的实现实例。
假设我们有一个UserDAO接口及其实现类UserDAOImp:
UserDAO.java:
public interface UserDAO {
&&& public void saveUser(User user);
}
UserDAOImp.java:
public class UserDAOImp implements UserDAO{
&&& public void saveUser(User user) {
&&& ……
&&& }
}
UserDAOImp.saveUser方法中实现了针对User对象的数据库持久逻辑。
如果我们希望在UserDAOImp.saveUser方法执行前后追加一些处理过程,如启动/
提交事务,而不影响外部代码的调用逻辑,那么,增加一个Proxy类是个不错的选择:
UserDAOProxy.java
public class UserDAOProxy implements UserDAO {
& private UserDAO userDAO;
& public UserDAOProxy(UserDAO userDAO) {
&&& this.userDAO = userDAO;
& }
& public void saveUser(User user) {
&&& UserTransaction tx =
&&& try {
&&&&&&&& tx = (UserTransaction) (
&&&&&&&&&&& new InitialContext().lookup("java/tx")
&&&&&&&& );
&&&&&&&& userDAO.saveUser(user);
&&&&&&&& tx.commit();
&&&& } catch (Exception ex) {
&&&& if (null!=tx){
&&&&&& try {
&&&&&&&&& tx.rollback();
&&&&&& }catch(Exception e) {
&&&&&& }
&&&& }
&& }
UserDAOProxy同样是UserDAO接口的实现,对于调用者而言,saveUser方法的使用完全相同,不同的是内部实现机制已经发生了一些变化――我们在UserDAOProxy中为UserDAO.saveUser方法套上了一个JTA事务管理的外壳。
上面是静态Proxy模式的一个典型实现。
现在假设系统中有20个类似的接口,针对每个接口实现一个Proxy,实在是个繁琐无味的苦力工程。
Dynamic Proxy的出现,为这个问题提供了一个更加聪明的解决方案。
我们来看看怎样通过Dynamic Proxy解决上面的问题:
public class TxHandler implements InvocationHandler {
&&& private Object originalO
&&& public Object bind(Object obj) {
&&&&&&& this.originalObject =
&&&&&&& return Proxy.newProxyInstance(
&&&&&&&&&&& obj.getClass().getClassLoader(),
&&&&&&&&&&& obj.getClass().getInterfaces(),
&&&&&&&&&&& this
&&&&&&&& );
&&& }
&&& public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
&&&&&& Object result =
&&&&&& if (!method.getName().startsWith("save")) {
&&&&&&& UserTransaction tx =
&&&&&&& try {
&&&&&&&&&&&&&&& tx = (UserTransaction) (
&&&&&&&&&&&&&&&&&&&& new InitialContext().lookup("java/tx")
&&&&&&&&&&&&&&&&&&& );
&&&&&&&&&&&&&&& result = method.invoke(originalObject, args);
&&&&&&&&&&&&
&&&&&&&&&&&&&&& tx.commit();
&&&&&&&&&&& } catch (Exception ex) {
&&&&&&&&& if (null != tx) {
&&&&&&&&&&&&& try {
&&&&&&&&&&&&&&&&& tx.rollback();
&&&&&&&&&&&&& } catch (Exception e) {
&&&&&&&&&&&&& }
&&&&&&&&&& }
&&&&&&&& }
&&&&& } else {
&&&&&&&&&& result = method.invoke(originalObject, args);
&&&&& }
&&&&&
&& }
}
首先注意到,上面这段代码中,并没有出现与具体应用层相关的接口或者类引用。也就是说,这个代理类适用于所有接口的实现。
其中的关键在两个部分:
1.
& return Proxy.newProxyInstance(
&&&& obj.getClass().getClassLoader(),
&&&& obj.getClass().getInterfaces(),
&&&& this);
java.lang.reflect.Proxy.newProxyInstance方法根据传入的接口类型(obj.getClass().getInterfaces())动态构造一个代理类实例返回,这个代理类是JVM在内存中动态构造的动态类,它实现了传入的接口列表中所包含的所有接口。
这里也可以看出,Dynamic Proxy要求所代理的类必须是某个接口的实现(obj.getClass().getInterfaces()不可为空),否则无法为其构造响应的动态类。这也就是为什么Spring对接口实现类通过Dynamic Proxy实现AOP。
2.
&& public Object invoke(Object proxy, Method method, Object[] args)
&& throws Throwable {
&&&&& ……
&&&&&& result = method.invoke(originalObject, args);
&&&&& ……
&&&&&&
&& }
InvocationHandler.invoke方法将在被代理类的方法被调用之前触发。通过这个方法中,我们可以在被代理类方法调用的前后进行一些处理,如代码中所示,InvocationHandler.invoke方法的参数中传递了当前被调用的方法(Method),以及被
调用方法的参数。同时,我们可以通过Method.invoke方法调用被代理类的原始方法实现。这样,我们就可以在被代理类的方法调用前后大做文章。
在示例代码中,我们为所有名称以“save”开头的方法追加了JTA事务管理。
谈到这里,可以回忆一下Spring事务配置中的内容:
&property name="transactionAttributes"&
&& &props&
&&&&& &prop key="save*"&PROPAGATION_REQUIRED&/prop&
&&&&& &prop key="get*"&PROPAGATION_REQUIRED,readOnly&/prop&
&& &/props&
&/property&
想必大家已经猜测到Spring事务管理机制的实现原理。
是的,只需通过一个Dynamic Proxy对所有需要事务管理的Bean进行加载,并根据配置,在invoke方法中对当前调用的方法名进行判定,并为其加上合适的事务管理代码,那么就实现了Spring式的事务管理。当然,Spring中的AOP实现更为复杂和灵活,不过基本原理一致。
Spring中Dynamic Proxy AOP实现类为:
org.springframework.aop.framework.JdkDynamicAopProxy
浏览: 245097 次
来自: 天津
如果设置了连接需要密码,Dynamic Broker-Clus ...
请问你的最后一种模式Broker-C节点是不是应该也要修改持久 ...
longshao_feng 写道楼主使用 文件共享 模式的ma ...
楼主使用 文件共享 模式的master-slave,produ ...
感触很深,必定谨记!> Spring学习笔记之aop动态代理(3)
Spring学习笔记之aop动态代理(3)
相关推荐:相信读者用过Spring的AOP自定义标签,也就是在bean.xml的文件中添加&aop:aspect-autoproxy/&,注解了这句话后,Spring就会支持注解AOP。那么Spring是如何去处理呢?接下来笔者就带领读者去了解Spring的动态AOP自定义标签的源码。下面我们先来看Spring的时序图
Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点:1、在该系统中有多少的dao就的写多少的proxy,麻烦2、如果目标接口有方法的改动,则proxy也需要改动。 PersonDao.javapublic interface PersonDao {public void savePerson();}PersonDaoImpl.javapublic class PersonDaoImpl implements PersonDao{public void savePerson() {System.out.println(&save person&);}}PersonDaoProxy.javapublic class PersonDaoProxy implements PersonDao{private PersonDao personDprivate Trapublic PersonDaoProxy(PersonDao personDao,Transaction transaction){this.personDao = personDthis.transaction =}public void savePerson() {this.transaction.beginTransaction();this.personDao.savePerson();mit();}}Transaction.javapublic class Transaction {public void beginTransaction(){System.out.println(&begin transaction&);}public void commit(){System.out.println(&commit&);}}ProxyTest.java/* * 静态代码模式: *1、在该系统中,有多少dao,就得写多少proxy *2、如果目标接口有方法的改动,则proxy也得做相应的修改 */public class ProxyTest {@Testpublic void testProxy(){PersonDao personDao = new PersonDaoImpl();Transaction transaction = new Transaction();PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction);proxy.savePerson();}}2.0 动态代理模式–jdkproxy(优点:动态的产生代理对象,所以只需要一个拦截器就可以了。缺点:如果invoke方法做事务的判断,将很复杂。程序员还是写拦截器了,写拦截器的invoke方法了,所以invoke方法还需要修改)问题:1、拦截器的invoke方法在什么时候被调用的在代理对象调用方法的时候,进入了拦截器中的invoke方法。2、拦截器总的method参数是什么?在什么时候由实参传递给形参的。代理对象的方法的名称是什么,method的参数的名称就是什么。代理对象调用方法的时候进入了拦截器的invoke方法,这个时候传递参数。3、生成的代理对象实现了接口,代理对象的方法体的内容是什么?方法体的内容就是拦截器中的invoke方法体的内容。说明:目标类和代理类实现了共同的接口。MyInterceptor.java/** * 1、引入personDao和Transaction * 2、完成invoke方法 * @author zd * */public class MyInterceptor implements InvocationHandler{private Oprivate Trapublic MyInterceptor(Object target,Transaction transaction){this.target =this.transaction =}public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {if(method.getName().equals(&savePerson&)||method.getName().equals(&updatePerson&)){this.transaction.beginTransaction();method.invoke(this.target, args);//调用目标类的目标方法mit();}else{method.invoke(this.target, args);//调用目标类的目标方法}}}PersonDao.javapublic interface PersonDao {public void savePerson();}PersonDaoImpl.javapublic class PersonDaoImpl implements PersonDao{public void savePerson() {System.out.println(&save person&);}}/* * *问题: *1、拦截器中的invoke方法在什么时候被调用的 *在代理对象调用方法的时候,进入了拦截器中的invoke方法 *2、拦截器中的method参数是什么?在什么时候由实参传递给形参的 *代理对象的方法的名称是什么,method参数就是什么 *代理对象调用方法的时候,进入了拦截器中的invoke方法,这个时候,传递参数 *3、生成的代理对象实现了接口,代理对象的方法体的内容是什么? *方法体的内容就是拦截器中的invoke方法体的内容 */Transaction.java public class Transaction {public void beginTransaction(){System.out.println(&begin transaction&);}public void commit(){System.out.println(&commit&);}}ProxyTest.java/** * jdkproxy的优点 *动态的产生代理对象,所以只需要用一个拦截器就可以了 * jdkproxy的缺点 *如果在invoke方法中做事务的判断,将是一件很复杂的事情 *程序员还是写拦截器了,写拦截器中的invoke方法了,所以invoke方法还需要修改 **说明: *目标类和代理类实现了共同的接口 * @author zd * */public class ProxyTest {@Testpublic void testProxy(){PersonDao target = new PersonDaoImpl();Transaction transaction = new Transaction();MyInterceptor interceptor = new MyInterceptor(target, transaction);/*** 第一个参数目标类的类加载器* 第二个参数目标类实现的所有的接口* 第三个参数拦截器*/PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), interceptor);personDao.savePerson();}}3.0 动态代理模式–cglibjar包cglib-nodep-2.1.3说明:目标类是代理类的父类。PersonDaoImpl.javapublic class PersonDaoImpl implements PersonDao{public void savePerson() {System.out.println(&save person&);}}Transaction.javapublic class Transaction {public void beginTransaction(){System.out.println(&begin transaction&);}public void commit(){System.out.println(&commit&);}}MyInterceptor.java/** * 1、引入personDao和Transaction * 2、完成invoke方法 * @author zd * */public class MyInterceptor implements MethodInterceptor{private Oprivate Trapublic MyInterceptor(Object target,Transaction transaction){this.target =this.transaction =}public Object createProxy(){Enhancer enhancer = new Enhancer();enhancer.setCallback(this);//this代表拦截器对象enhancer.setSuperclass(target.getClass());//设置代理类的父类为目标类return enhancer.create();}/*** 该方法的内容和jdkpoxy中的invoke方法的内容是一样的*/public Object intercept(Object arg0, Method method,Object[] args,MethodProxy arg3) throws Throwable {this.transaction.beginTransaction();method.invoke(this.target, args);mit();}}PersonDao.javapublic interface PersonDao {public void savePerson();}ProxyTest.java/** * 目标类是代理类的父类 * @author zd * */public class ProxyTest {@Testpublic void testProxy(){PersonDaoImpl target = new PersonDaoImpl();Transaction transaction = new Transaction();MyInterceptor interceptor = new MyInterceptor(target, transaction);PersonDaoImpl proxy = (PersonDaoImpl)interceptor.createProxy();proxy.savePerson();}}4.0 spring aop的概念切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事物管理是J2EE应用中一个横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。连接点(joinpoint):在程序执行过程中某个特定的点,比如某方法调用时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。通知(Advice):在切面的某个特定连接点执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知。(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。切入点(Piontcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行。(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用Aspect切入点语法。引入(Introduction):用来给一个模型声明额外的方法或属性(也被称为连接类型声明)(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使用一个bean实现IsModified接口,以便简化缓存机制。目标对象(Target Object):被一个或者多个切面所通知的对象。也被称做通知(adviced)对象。既然Spring AOP是通过运行代理实现的,这个对象永远是一个被代理(Proxied)对象。AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。织入(Weaving):把切面连接到其他的应用程序类型或者对象,并创建一个被通知的对象。这些可以编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。JDKProxy代理SpringAop目标对象目标对象拦截器类切面拦截器类中的方法通知被拦截到的目标类中方法的集合切入点在客户端调用的方法(目标类目标方法)连接点代理类AOP代理代理类的代理方法生成的过程织入通知根据拦截目标类中的目标方法的位置不一样可以分为:前置通知、后置通知、最终通知、环绕通知、异常通知说明:1、通知就是切面中的方法;2、代理对象的方法=通知+目标方法3、连接点就是目标接口中的一个方法而已4、拦截器中的invoke方法就是代理对象的方法=通知+目标方法5、在现实的开发过程中,通知和目标方法时完全松耦合的通知:就是切面的方法织入:形成代理对象的方法的过程就是织入连接点:客户端调用哪个方法,该方法就是连接点。只有符合切入点,才让通知和目标方法结合在一起。$(function () {$('pre.prettyprint code').each(function () {var lines = $(this).text().split('\n').var $numbering = $('&ul/&').addClass('pre-numbering').hide();$(this).addClass('has-numbering').parent().append($numbering);for (i = 1; i &= i++) {$numbering.append($('&li/&').text(i));};$numbering.fadeIn(1700);});});
Spring学习笔记之aop动态代理(3) 1.0 静态代理模式的缺点:
1、在该系统中有多少的dao就的写多少的proxy,麻烦
2、如果目标接口有方法的改动,则proxy也需要改动。 PersonDao.jav
------分隔线----------------------------
相关阅读排行
相关最新文章
Copyright 2012- ( Coin163 ) All Rights Reserved &&一、SpringAOP:
   ⒈AOP:Aspect Oriented Programming&面向切面编程, 实现的是核心业务和非核心业务之间的的分离,让核心类只做核心业务,代理类只做非核心业务。
   &⒉目的:  
      ⑴、把核心业务和非核心业务进行分离    
       ⑵、把多个非核心业务处理(点)变成一个切面(之前的非核心业务代码需要写多次变成只需要写一次。)
   ⒊要求:只有当核心类中有多个业务需要进行处理的时候使用AOP较为合理,如果只有一个业务需要被处理那么就没有必要使用AOP了。
二、静态代理:
   1、需要知道核心类(被代理类)是哪一个类,并且有什么方法。 
   2、非核心的代码需要重复写多次,显得代码的结构臃肿,形成代码冗余。
   3、非核心类(代理类)需要实现核心类(被代理类)实现的接口,也就是他们需要实现共同的接口,但是以核心类实现的接口(被代理类)为准。
三、动态代理:
   1、不需要知道核心类(被代理类)具体是什么类。
   2、非核心类(代理类)需要实现InvocationHandler接口。   
四、静态代理示例:
    1、业务介绍:
      假定高三学生为核心类,学生的家人是代理类。高三学生需要做的核心业务有:在家学习(studyAtHome)、在学校学习(studyAtHome);家人需要做的非核心业务为:准备饭菜(买、洗、炒、煮饭)。准备补品(购买、熬制、加佐料)。
    2、具体代码:
      ⑴、创建一个高三学生的接口:G3Student
        
package aop_001;
//首先定义一个接口,用来高三学生来是实现,
//在这个接口中声明一个在家学习和一个在学校学习的方法
public interface G3Student {
public void studyAtHome(String core);
public void studyAtSchool(String core);
       ⑵、创建一个高三学生实现类:G3Student_boy,并且这个类实现高三学生接口(G3Student)
package aop_001;
//定义一个高三男孩的类(目标对象、核心对象、target对象),实现了高三学生的接口。
public class G3Student_boy implements G3Student {
//高三男孩 的第一个业务流程:在家学习
public void studyAtHome(String core) {
//核心的事情在家学习。
System.out.println(core+"在HOME学习");
//高三男孩 的第二个业务流程:在学校学习
public void studyAtSchool(String core) {
//核心的事情在家学习。
System.out.println(core+"在SCHOOOL学习");
&      &
        ⑶、创建一个高三学生的代理类:G3Student_proxy,并且实现了高三学生接口:G3Student。红色字体需要理解
package aop_001;
代理对象(G3Student_proxy)的目的是帮助核心对象(G3Student_boy / G3Student_girl)做非核心的事情。
但是代理对象(G3Student_proxy)必须和核心对象(G3Student_boy / G3Student_girl)实现共同的接口。
public class G3Student_proxy implements G3Student {
//定义一个高三学生接口 作为属性,目的是就是在处理完代理需要做的事情之后调用高三男孩或者是高三女孩需要做的核心业务,
//但是不是代理具体去做这些核心的事情,只是调用它们而已。
private G3Student G3S;
//创建一个代理的参数为 高三学生接口 的构造函数,判断但传入的字符串为boy就构造一个高三男孩的实例,如果传入的参数为girl就构造一个高三女孩的实例。
public G3Student_proxy(String sex) {
if("boy".equals(sex)){
G3S = new G3Student_boy();
}else if("girl".equals(sex)){
G3S = new G3Student_girl();
public void studyAtHome(String core){
//这个是代理(G3Student_proxy)准备饭菜的需要做的流程:
System.out.println("代理:准备买菜");
System.out.println("代理:准备洗菜");
System.out.println("代理:准备炒菜");
System.out.println("代理:准备煮饭");
System.out.println("-----------------");
//通过定义的属性,并且在调用G3Student_proxy的含参数的构造函数创建相对应的实例,调用这个具体的实例的方法
G3S.studyAtHome(core);
     //这个是代理(G3Student_proxy)准备补品的需要做的流程:
System.out.println("-----------------");
System.out.println("代理 :购买补品");
System.out.println("代理 :熬制部品");
System.out.println("代理 :加入佐料");
System.out.println();
public void studyAtSchool(String core) {
//这个是代理准备(G3Student_proxy)饭菜的需要做的流程:
System.out.println("代理:准备买菜");
System.out.println("代理:准备洗菜");
System.out.println("代理:准备炒菜");
System.out.println("代理:准备煮饭");
System.out.println("-----------------");
//通过定义的属性,并且在调用G3Student_proxy的含参数的构造函数创建相对应的实例,调用这个具体的实例的方法
G3S.studyAtSchool(core);
System.out.println("-----------------");
//这个是代理(G3Student_proxy)准备补品的需要做的流程:
System.out.println("代理 :购买补品");
System.out.println("代理 :熬制部品");
System.out.println("代理 :加入佐料");
System.out.println();
        
        ⑷、进行测试:定义一个测试类 Test
package aop_001;
public class Test {
public static void main(String[] args) {
//创建一个代理对象,并且传入相对应的参数构造出具体的实例
G3Student b = new G3Student_proxy("boy");
//通过这个代理对象执行相关的方法(代理对象和核心对象有共同接口)
b.studyAtHome("小明");
b.studyAtSchool("小明");
        测试结果:
& & & & & & & & & & & & & & & &
   3、小结:
      由上面的例子我们可以简单模拟一个静态代理的实例,但是我们发现,这个代理做的事情会因为核心对象业务多而变得多起来,而且这些代理做的事情都是相同的没有变化的:
& & & & & & & & & &&& &
      并且,如果我们要修改这些流程中的某一个流程的时候会发现要改多处,而且都是相同的代码,所以这个时候使用动态代理就可以轻松解决这个问题。
& & & & & & & &谢谢浏览 !
     
阅读(...) 评论()Spring中Aop不能代理继承自扩展了接口的父类
错误原因:
配置事务为adminDAOImpl生成了代理,所以在下面action中注入的将是代理对象(提示信息中的 [$Proxy12]
)而不是原来的adminDAOImpl对象,这就产生了上面错误信息。
解决办法:
使用cgilib来实现AOP,定义proxy-target-class="true"
;proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class
属性值被设置为true,那么基于类的代理被创建,产生的代理对象会instanceof原来的类。
&&&aop:config
proxy-target-class="true"& &
& &&aop:pointcut
id="daoPointCut" expression="execution(*
com.chemmade.adminbg.dao.impl..*.*(..))" /&
& &&aop:advisor
advice-ref="txAdvice" pointcut-ref="daoPointCut"/&
&&/aop:config&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 spring aop 参数传递 的文章

 

随机推荐