动态代理的深入了解

时间:2020-12-22 05:06:12

总结结构:

   静态代理模式的缺点:

      1、如果一个系统中有100Dao,则创建100个代理对象

      2、如果一个dao中有很多方法需要事务,则代理对象的方法中重复代码还是很多

      3、由第一点和第二点可以得出:proxy的重用性不强

 

因为静态代理无法满足开发需求所以 引出动态代理

 

动态代理模式:

   1、产生的代理对象和目标对象实现了共同的接口

       jdk动态代理

   2、代理对象是目标对象的子类

       hibernate: Person person = session.load(Person.class,1L);  javassisit

       spring:cglib动态代理

 

jdk的动态代理:

   1、因为是用jdkAPI做到的

   2、代理对象是动态产生的

cglib产生的代理类是目标类的子类

 

注意事项:

    1、拦截器中invoke方法体的内容就是代理对象方法体的内容

    2、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体

    3、拦截器中invoke方法的method参数是在调用的时候赋值的

 

aop:

   1、切面

        事务、日志、安全性框架、权限等都是切面  

   2、通知

      切面中的方法就是通知

   3、目标类

   4、切入点

         只有符合切入点,才能让通知和目标方法结合在一起

   5、织入:

         形成代理对象的方法的过程

         

 

好处:

   事务、日志、安全性框架、权限、目标方法之间完全是松耦合的

 

 

jdk的动态代理举例

PersonDao.java

1 package cn.itcast.jdkproxy.sh;
2 
3 public interface PersonDao {
4     public void savePerson();
5     public void updatePerson();
6     public void deletePerson();
7 }

PersonDaoImpl.java

 1 package cn.itcast.jdkproxy.sh;
 2 
 3 public class PersonDaoImpl implements PersonDao{
 4     public void deletePerson() {
 5         System.out.println("delete person");
 6     }
 7     public void savePerson() {
 8         System.out.println("save person");
 9     }
10     public void updatePerson() {
11         System.out.println("update person");
12     }
13 }

Transaction.java

 1 package cn.itcast.jdkproxy.sh;
 2 
 3 public class Transaction {
 4     public void beginTransaction(){
 5         System.out.println("开启事务 ");
 6     }
 7     public void commit(){
 8         System.out.println("事务提交");
 9     }
10 }

PersonInterceptor.java

 1 package cn.itcast.jdkproxy.sh;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 
 6 /**
 7  * 拦截器
 8  * @author Think
 9  *   1、引入目标类
10  *   2、引入事务
11  *   3、通过构造函数给目标类和事务赋值
12  *   4、填充invoke方法
13  *
14  */
15 public class PersonInterceptor implements InvocationHandler{
16     
17     private Object target;//目标类
18     private Transaction transaction;//引入事务
19     
20     public PersonInterceptor(Object target,Transaction transaction){
21         this.target = target;
22         this.transaction = transaction;
23     }
24     
25 
26     @Override
27     public Object invoke(Object proxy, Method method, Object[] args)
28             throws Throwable {
29         // TODO Auto-generated method stub
30         this.transaction.beginTransaction();
31         method.invoke(this.target, args);//调用目标类的方法
32         this.transaction.commit();
33         return null;
34     }
35 
36 }

ProxyTest.java

 1 package cn.itcast.jdkproxy.sh;
 2 
 3 import java.lang.reflect.Proxy;
 4 
 5 import org.junit.Test;
 6 import org.springframework.context.ApplicationContext;
 7 import org.springframework.context.support.ClassPathXmlApplicationContext;
 8 
 9 public class ProxyTest {
10     @Test
11     public void test(){
12         Object target = new PersonDaoImpl();
13         Transaction transaction = new Transaction();
14         PersonInterceptor interceptor = new PersonInterceptor(target, transaction);
15         /**
16          * 1、目标类的类加载器
17          * 2、目标类实现的所有的接口
18          * 3、拦截器
19          */
20         PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
21         personDao.deletePerson();
22     }
23 }

实现jdk的动态代理,以上例子的改进可以在PersonInterceptor.java中添加成员函数

private List<Interceptor> interceptors;

然后让切面都继承 Interceptor接口,这个接口是自己定义的。

 

改进版例子:

1 package cn.itcast.jdkproxy.salary;
2 
3 public interface Interceptor {
4     public void interceptor();
5 }

 

其它类:很多

 1 package cn.itcast.jdkproxy.salary;
 2 
 3 public class Logger implements Interceptor{
 4 
 5     @Override
 6     public void interceptor() {
 7         // TODO Auto-generated method stub
 8         System.out.println("logging");
 9     }
10     
11 }

 

 

 1 package cn.itcast.jdkproxy.salary;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.util.List;
 6 
 7 public class SalaryInterceptor implements InvocationHandler{
 8 
 9     
10     private Object target;
11     
12     private List<Interceptor> interceptors;
13     
14     public SalaryInterceptor(Object target,List<Interceptor> interceptors){
15         this.target = target;
16         this.interceptors = interceptors;
17     }
18     
19     @Override
20     public Object invoke(Object proxy, Method method, Object[] args)
21             throws Throwable {
22         for(Interceptor interceptor:interceptors){
23             interceptor.interceptor();
24         }
25         method.invoke(this.target, args);
26         return null;
27     }
28 
29 }

客户端测试类

 1 package cn.itcast.jdkproxy.salary;
 2 
 3 import java.lang.reflect.Proxy;
 4 import java.util.ArrayList;
 5 import java.util.List;
 6 
 7 import org.junit.Test;
 8 
 9 public class SalaryTest {
10     @Test
11     public void test(){
12         Object target = new SalaryManagerImpl();
13         Logger logger = new Logger();
14         Security security = new Security();
15         Privilege privilege = new Privilege();
16         List<Interceptor> interceptors = new ArrayList<Interceptor>();
17         interceptors.add(logger);
18         interceptors.add(security);
19         interceptors.add(privilege);
20         SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
21         SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
22         salaryManager.showSalary();
23     }
24 }