崇峰一号花园:java动态代理,spring AOP动态代理

来源:百度文库 编辑:中财网 时间:2024/04/29 22:47:53
java动态代理 Proxy.newProxyInstance方法,将动态产生一个类$Proxy0,这个类既继承了Proxv又实现了所指定类的接口. 该接口有一个方法,令为action,则$Proxy0中实现的action将直接调用InvocationHandler对象的invoke方法.
实现的接口的方法,
   动态代理的意义:在函数可能变动的地方,使用动态代理封装这个变化点,让程序员在另一处变动。这处就是继承InvocationHandler的子类中。
 
    在程序运行时,让封装点按需要变动。还必须对动态代理进行封装:
    在这个封装类中,将使用类反射器。把已经变动好的类文件的路径,传给这个封装类,再经过类反射器得到这个变动好的类。注:这个变动好的类,就是继承了InvocationHandler的类。在下例中,就是指ActionHandler
 
package javaapplication4;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
//---------元接口---------要变动方法所依存的接口
 interface IAction   {
     public   void action();
}
 
//----------元类----------要变动方法所依存的类
 class CAction implements IAction {
    public void action() {
        System.out.println("正在行动");
    }
}
 
 //---invoke ---就是变更后,所期待的方法.java的proxy 将调用这个类,即方法//invoke
class ActionHandler implements InvocationHandler {
    private Object actionObj;
    public Object binder(Object actionObj) {
        this.actionObj=actionObj;
        return Proxy.newProxyInstance(actionObj.getClass().getClassLoader(),
                actionObj.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        System.out.println("行动前");
        try {
            result = method.invoke(actionObj, args);
        } catch (Exception e) {
        }
        System.out.println("行动后");
        return result;
    }
}
 
 
public class Dd {
    public static void main(String[] args) {
        IAction ia = (IAction) new ActionHandler()
                .binder(new CAction());
        ia.action();
    }
}
 
 Spring AOP 动态代理 首先你得认识AOP:
AOP ----切面编程
所谓切面编程:在不改变原方法(令为methodA)的定义与使用、也不改变原程序的流程的情况下,变更该methodA的功能。在变更时,最激动人心的时能获得methodA的类的对象,meahtoidA的参数,也可获得mehodA执行的结果,还能得到调用meahtoidA的对象。
    简单理解:允许用户在指定地方,插入新的函数,
包括:
1 methodA运行前,执行用户指定的其它方法methodOther,然后返回
2 methodA运行完毕,执行用户指的其它方法methodOther,然后返回
3 , 在执行methodA的地方,变成执行在用户指定的其它方法methodOther,
在methodOther方法中, methodA运不运行,何时运行,随用户自行安排.,然后返回
4 methodA执行出现异常时,执行用户指定的其它方法methodOther,然后返回。
产生动机:
在一个程序中,当我们要 使用一个方法(令为methodA);由于不同的用户对methodA的功能要 求不一样,因此在这个methodA的地方就出现了变化点。所以要在这个变化点上进行封装,留下一个可扩展的接口,便于日后修改维护。
 
本质:
     1 Aop核心是一个适配器,把变动前的方法,与变动后的方法联接在一起。
     2 这个适配器实现的核心是动态代理Proxy机制
3  四个核心子接口:
a  MethodBeforeAdvice ----methodA函数调用前执行用户定义的方法
b AfterReturningAdvice ----- methodA函数调后执行用户定义的方法
c MethodInterceptor -------彻底变更MethodA函数为用户定义的方法
d ThrowsAdvice------methodA函数调用出现异常执行用户定义的方法
      
 
具体实例1 :
   有一个购书行为,在购书行为发生前,增加欢迎信息。
 
1 有一购书接口
interface BuyBook {
   public void buyBook(String customer,String book);
}
 
 2 实现了该接口的对象
 public class MyBuyBook implements BuyBook {
    public void buyBook(String customer,String book){
        System.out.println(customer+"你好你成功购了一本"+book+"!");
     }
}
   3 客户端源代码 test.java
      package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("myBuyBookTarget ");
        buybook.buyBook("小东", "《楚留香》");
    }
}
2        配置文件 test.xml 位于源代码文件夹下的config文件中。
 


   

 
此时运行程序仅出现:
小东你好你成功购了一本《楚留香》
 
3        现在仅修改配置文件,增加一个实现了MethodBeforeAdvice 接口的类,就更改了购书行为buyBook(------小东你好你成功购了一本《楚留香》!)
3),让它具备购书前就有欢迎功能(---------欢迎光临!小东!。)
 class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method arg0, Object[] arg1, Object target)           throws Throwable {
        String customer=(String)arg1[0];     
        System.out.println("欢迎光临!"+customer+"!");  
    }
}
其中:
1org.springframework.aop.MethodBeforeAdvice;接口,有一个方法
public void before(Method arg0, Object[] arg1, Object target)
            throws Throwable
其中:arg0-----要变更函数,即切入点,即上面说到的方法MethodA,也即buybook
arg1-----要变更函数的参数。即MethodA方法的参数,也即是customer、book。
target----变更函数依附的对象,即myBuyBookTarget
 
4        修改后的配置文件test.xml
 


   
   
   
       
       
           
                  myBeforeAdvice
           

       

       
   


 
 
其中:A
定义了扩展了的功能对象
 

其它三类子接口,都必须定义该bean
 

定义了切面----即要扩展函所依附类所遵循的接口。
 

       
              myBeforeAdvice
        

   

所增加的功能,作为list数组的值放进去。即这个数组可放其它三种子接口的对象。如扩展前与扩展后的功能的对象分别是myBeforeAdvice、myAfterAdvice则6中test.xml配置文件仅如下修改,其它地方不变。

       
              myBeforeAdvice
              myAfterAdvice
        

   

 
注:此时运行程序,会出现:
欢迎光临!小东!
小东你好你成功购了一本《楚留香》
 
5        完整源代码
a MyBuyBook.java
package javaapplication2;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
 
interface BuyBook {
   public void buyBook(String customer,String book);
}
 
public class MyBuyBook implements BuyBook {
    public void buyBook(String customer,String book){
        System.out.println(customer+"你好你成功购了一本"+book+"!");
     }
}
 
class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method arg0, Object[] arg1, Object target)
            throws Throwable {
        String customer=(String)arg1[0];     
        System.out.println("欢迎光临!"+customer+"!");  
    }
}
 
 
b 测试源代码test.java
package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("buyBook");
        buybook.buyBook("小东", "《楚留香》");
    }
}
 
c 配置文件test.xml见6
    
具体实例2 :
   有一个购书行为,在购书行为发生后,增加欢送信息。
 
1 有一购书接口
interface BuyBook {
   public void buyBook(String customer,String book);
}
 
 2 实现了该接口的对象
 public class MyBuyBook implements BuyBook {
    public void buyBook(String customer,String book){
        System.out.println(customer+"你好你成功购了一本"+book+"!");
     }
}
   3 客户端源代码 test.java
      package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("myBuyBookTarget ");
        buybook.buyBook("小东", "《楚留香》");
    }
}
4 配置文件 test.xml 位于源代码文件夹下的config文件中。
 


   

 
此时运行程序仅出现:
小东你好你成功购了一本《楚留香》
 
5 现在仅修改配置文件,增加一个实现了AfterReturningAdvice接口的类,就更改了购书行为buyBook------小东你好你成功购了一本《楚留香》!
),让它具备购书后就有欢送功能---------欢迎下次再来!小东!。
 class MyAfterAdvice implements AfterReturningAdvice {
     public void afterReturning(Object arg0, Method arg1, Object[] arg2,
          Object arg3) throws Throwable {
        String customer=(String)arg2[0];     
        System.out.println("欢迎下次再来!"+customer+"!");  
    }
}
其中:
org.springframework.aop.AfterReturningAdvice;接口,有一个方法
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
          Object arg3) throws Throwable
其中:
     arg0------要变更函数执行结果,即MethodA的结果,也即buybook的执行结果
arg1-----要变更函数,即切入点,即MethodA,也即buybook
arg2-----要变更函数的参数。即MethodA方法的参数,也即是customer、book。
arg3----变更函数依附的对象,即myBuyBookTarget
 
1        修改后的配置文件test.xml
 


   
   
   
       
       
           
                  myAfterAdvice
           

       

       
   


 
 
其中:A 
定义了扩展了的功能对象
 

其它三类子接口,都必须定义该bean
 

定义了切面----即要扩展函所依附类所遵循的接口。
 

       
              myAfterAdvice
        

   

所增加的功能,作为list数组的值放进去。即这个数组可放其它三种子接口的对象。如扩展前与扩展后的功能的对象分别是myBeforeAdvice、myAfterAdvice则6中test.xml配置文件仅如下修改,其它地方不变。

       
              myBeforeAdvice
              myAfterAdvice
        

   

 
注:此时运行程序,会出现:
小东你好你成功购了一本《楚留香》
欢迎下次再来!小东!
 
2        完整源代码
a MyBuyBook.java
package javaapplication4;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
 
interface BuyBook {
   public String buyBook(String customer,String book);
}
 
public class MyBuyBook implements BuyBook {
    public String buyBook(String customer,String book){
        System.out.println(customer+"你好你成功购了一本"+book+"!");
        return "aaa";
     }
}
class MyAfterAdvice implements AfterReturningAdvice {
     public void afterReturning(Object arg0, Method arg1, Object[] arg2,
          Object arg3) throws Throwable {
        String customer=(String)arg2[0];     
        System.out.println("欢迎下次再来!"+customer+"!");  
    }
}
b 测试源代码test.java
 package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("buyBook");
        buybook.buyBook("小东", "《楚留香》");
    }
}
 
c 配置文件test.xml见6
 
具体实例3 :
   有一个购书行为,在购书行为发生时,只允许顾客购一本打折书。原来没限制。
 
1 有一购书接口
interface BuyBook {
   public void buyBook(String customer,String book);
}
 
 2 实现了该接口的对象
 public class MyBuyBook implements BuyBook {
    public void buyBook(String customer,String book){
        System.out.println(customer+"你好你成功购了一本"+book+"!");
     }
}
   3 客户端源代码 test.java
      package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("myBuyBookTarget ");
        buybook.buyBook("小东", "《楚留香》");
        buybook.buyBook("小东", "《小李飞刀》");
    }
}
4 配置文件 test.xml 位于源代码文件夹下的config文件中。
 


   

 
此时运行程序仅出现:
小东你好你成功购了一本《楚留香》!
小东你好你成功购了一本《小李飞刀》!
 
5 现在仅修改配置文件,增加一个实现了MethodInterceptor接口的类,就更改了购书行为buyBook(------小东你好你成功购了一本《楚留香》!
),当发现顾客已经购了一本打折书时,中止这次购买,并给出提示---------“注意,一名顾客只能买一本打折书!。”
 class MyAroundAdvice implements MethodInterceptor {
    private Set customers=new HashSet();    //保存购过书的顾客信息
    public Object invoke(MethodInvocation invocation) throws Throwable {
    String customer=(String)invocation.getArguments()[0];
    Object result=null;
    if(customers.contains(customer)){
         System.out.println("注意,一名顾客只能买一本打折书!");
    } else{
         result=invocation.proceed();
 //调用MyBuyBook中的buyBook方法,即真实操作
    }
    customers.add(customer);
    return result;
 }
 
}
其中:
org.springframework.aop. MethodInterceptor;接口,有一个方法
invoke(MethodInvocation invocation) throws Throwable {
 
其中:
     invocation ------ 对要变更函数进行封装的数据包
invocation.proceed –--得到变更函数,即buyBook方法。
invocation.getArguments()-----得到变更函数的参数。 即buyBook的参数{custorm,book}
 
6   修改后的配置文件test.xml
 


   
   
   
       
       
           
                  myAroundAdvice
           

       

       
   


 
 
其中:

定义了扩展了的功能对象
 

其它三类子接口,都必须定义该bean
 

定义了切面----即要扩展函所依附类所遵循的接口。
 

       
              myAroundAdvice
        

   

所增加的功能,作为list数组的值放进去。即这个数组可放其它三种子接口的对象。如扩展前与扩展后的功能的对象分别是myAroundAdvice、myAfterAdvice则6中test.xml配置文件仅如下修改,其它地方不变。

       
              myAroundAdvice
              myAfterAdvice
        

   

 
注:此时运行程序,会出现:
小东你好你成功购了一本《楚留香》
注意,一名顾客只能买一本打折书!。
7 完整源代码
a MyBuyBook.java
 
package javaapplication4;
import java.util.HashSet;
import java.util.Set;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
interface BuyBook {
   public String buyBook(String customer,String book);
}
public class MyBuyBook implements BuyBook {
    public String buyBook(String customer,String book){
        System.out.println(customer+"你好你成功購了一本"+book+"!");
        return "aaa";
     }
}
 
class MyAroundAdvice implements MethodInterceptor {
 
    private Set customers=new HashSet();    //保存购过书的顾客信息
    public Object invoke(MethodInvocation invocation) throws Throwable {
    String customer=(String)invocation.getArguments()[0];
    Object result=null;
    if(customers.contains(customer)){
         System.out.println("注意,一名顾客只能买一本打折书!");
    } else{
         //调用MyBuyBook中的buyBook方法,即真实操作
         result=invocation.proceed();  
    }
    customers.add(customer);
    return result;
 }
 
}
 
b 测试源代码test.java
package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("buyBook");
        buybook.buyBook("小东", "《楚留香》");
    }
}
 
c 配置文件test.xml见6
 
具体实例4 :
   有一个购书行为,当购《大沙漠》时,这本书已经没有了,发出订货通知。
原来购书时,
1 定义一个异常,完整源码NoThisBookException.xml如下:
 package javaapplication4;
public class NoThisBookException extends RuntimeException {
     public NoThisBookException(String msg){
          super(msg);
     }
}
2 有一购书接口,其方法要抛出异常
interface BuyBook {
       public void buyBook(String customer,String book)throws NoThisBookException;
 
 
 3 实现了该接口的对象
public class MyBuyBook implements BuyBook {
public void buyBook(String customer,String book) throws NoThisBookException{
           if(book.equals("《大沙漠》"))
            throw new NoThisBookException("对不起,没有"+book+"存货了!");
            System.out.println(customer+",你好,你已经购买了一本"+book+"!");
     }
}
   4 客户端源代码 test.java
      package javaapplication2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
        ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("myBuyBookTarget ");
        buybook.buyBook("小东", "《楚留香》");
        buybook.buyBook("小东", "《大沙漠》");    }
}
 
5 配置文件 test.xml 位于源代码文件夹下的config文件中。
 


   

 
注:此时运行程序,会出现:
小东你好你成功购了一本《楚留香》
    Exception in thread "main" javaapplication4.NoThisBookException: 对不起,没有《大沙漠》存货了
 
6 现在仅修改配置文件,增加一个实现了ThrowsAdvice接口的类,就更改了购书行为buyBook(------小东你好你成功购了一本《楚留香》!
),当发现顾客要购《大沙漠》时,发出订货通知---------“通知仓库,赶紧加订书!”
 public class MyThrowsAdvice implements ThrowsAdvice {
    //可以定义多个方法,只要传入的参数是不同异常
    public void afterThrowing(NoThisBookException e){   
         System.out.print("通知仓库,赶紧加订书!");
    }
 
其中:
org.springframework.aop. ThrowsAdvice;接口,允许出现多个
afterThrowing 方法,只要其中的参数是不同异常类型就可以了
 
 
7 修改后的配置文件test.xml



   
   
   
       
       
           
                  myThrowsAdvice
           

       

       
   


 
 
其中:

定义了扩展了的功能对象
 

其它三类子接口,都必须定义该bean
 

定义了切面----即要扩展函所依附类所遵循的接口。
 

       
              myThrowsAdvice
        

   

所增加的功能,作为list数组的值放进去。即这个数组可放其它三种子接口的对象。如扩展前与扩展后的功能的对象分别是myThrowsAdvice、myAfterAdvice则6中test.xml配置文件仅如下修改,其它地方不变。

       
              myThrowsAdvice
              myAfterAdvice
        

   

 
注:此时运行程序,会出现:
小东你好你成功购了一本《楚留香》
 Exception in thread "main" javaapplication4.NoThisBookException: 对不起,没有《大沙漠》存货了
通知仓库,赶紧加订书!
 8  完整源代码
a 购书源代码。MyBuyBook.java
package javaapplication4;
 
interface BuyBook {
       public void buyBook(String customer,String book)throws NoThisBookException;
//    public void buyBook(String customer,String book);
}
 
public class MyBuyBook implements BuyBook {
    public void buyBook(String customer,String book)throws NoThisBookException{
        if(book.equals("《大沙漠》"))
            throw new NoThisBookException("对不起,没有"+book+"存货了!");
        System.out.println(customer+",你好,你已经购买了一本"+book+"!");
    }
}
 
b 已经变动的类,必须公共。MyThrowsAdvice.java
 
package javaapplication4;
import org.springframework.aop.ThrowsAdvice;
public class MyThrowsAdvice implements ThrowsAdvice {
    //可以定义多个方法,只要传入的参数是不同异常
    public void afterThrowing(NoThisBookException e){   
         System.out.print("通知仓库,赶紧加订书!");
    }
}
 
 
c 异常类源码,必须公共。 NoThisBookException.java
 
 package javaapplication4;
public class NoThisBookException extends RuntimeException {
     public NoThisBookException(String msg){
          super(msg);
     }
}
 
d 测试类源代码.test.java
 package javaapplication4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class test {
    public static void main(String args[]){
    ApplicationContext ctx=new FileSystemXmlApplicationContext("/src/config/test.xml");  
        BuyBook buybook=(BuyBook)ctx.getBean("buyBook");
        buybook.buyBook("小东", "《楚留香》");
        buybook.buyBook("小东", "《大沙漠》");
    }
}
 
e 配置类.test.xml 见7