Java进阶知识21 Spring的代理模式
本文知识点(目录):
1、概念
2、代理模式
2.1、静态代理
2.2、动态代理
2.3、Cglib子类代理
1、概念
代理(Proxy):是一种设计模式, 提供了 对目标对象的另外一种访问方式;即通过代理来访问目标对象*(好比:某位商家去找某个明星来代言他的产品,这位商家得先去找这位明星的经纪人)。
这样好处:可以在目标对象实现的基础上,增强额外的功能操作,也就是扩展目标对象的功能,过滤等。[用户------->代理------->目标对象]
2、代理模式
用到的jar包:junit-4.7.jar
实例:
1 public interface IUserDao {//接口类 2 public void save(); 3 } 4 5 //--------------------------------- 6 7 public class UserDao implements IUserDao { //实现类 8 9 @Override 10 public void save() { 11 // System.out.println("开启事务......"); //这一步,交给代理来做 12 13 System.out.println("保存用户成功!"); // session.save(obj); 14 15 // System.out.println("提交事务......"); //这一步,交给代理来做 16 } 17 }
静态代理工厂类
1 package com.shore.dao.proxy; 2 3 import com.shore.dao.IUserDao; 4 import com.shore.dao.impl.UserDao; 5 6 /** 7 * @author DSHORE/2019-10-28 8 * 9 */ 10 public class UserDaoProxy implements IUserDao { 11 // 目标对象 12 IUserDao target = new UserDao(); 13 14 // 构造器 15 public UserDaoProxy(IUserDao target) { 16 super(); 17 this.target = target; 18 } 19 20 @Override 21 public void save() { 22 System.out.println("开启事务......"); 23 24 target.save(); 25 26 System.out.println("提交事务......"); 27 } 28 }
测试类
1 package com.shore.test; 2 3 import org.junit.Test; 4 5 import com.shore.dao.IUserDao; 6 import com.shore.dao.impl.UserDao; 7 import com.shore.dao.proxy.UserDaoProxy; 8 9 /** 10 * @author DSHORE/2019-10-28 11 * 12 */ 13 public class MyTest { 14 @Test 15 public void testStaticProxy() { 16 //目标 17 IUserDao target = new UserDao(); 18 //代理 19 IUserDao userDaoProxy = new UserDaoProxy(target); 20 userDaoProxy.save(); 21 } 22 }
测试结果图:
总结:
1、代理对象,不需要实现接口;
2、代理对象的生成,是利用JDKAPI,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象、实现的接口的类型);
3、动态代理,JDK代理,接口代理;
用到的jar包:junit-4.7.jar
实例:
1 public interface IUserDao {//接口 2 public void save(); 3 } 4 5 //------------------------------------------ 6 7 public class UserDao implements IUserDao { //实现类 8 9 @Override 10 public void save() { 11 // System.out.println("开启事务======="); //动态代理,这一步交给代理工厂做了 12 13 System.out.println("保存用户成功!"); // 相当于session.save(obj); //持久化操作 14 15 // System.out.println("提交事务======="); //动态代理,这一步也是交给代理工厂做了 16 } 17 }
动态代理工厂类 (不需要 实现接口)
1 package com.shore.dao.factory; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 7 /** 8 * @author DSHORE/2019-10-28 9 * 10 */ 11 public class ProxyFactory { 12 13 // 维护一个目标对象 14 private Object target; 15 16 public ProxyFactory(Object target) { 17 super(); 18 this.setTarget(target); 19 } 20 21 // 创建代理 22 public Object getProxyInstance() throws IllegalArgumentException { 23 return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 定义代理类的类加载器 24 target.getClass().getInterfaces(), // 代理类要实现的接口列表(获取所有接口) 25 new InvocationHandler() { // 指派方法调用的调用处理程序 26 @Override 27 public Object invoke(Object proxy, Method method, 28 Object[] args) throws Throwable { 29 System.out.println("开启事务======="); 30 31 Object returnValue = method.invoke(target, args); // 放行 32 33 System.out.println("提交事务======="); 34 return returnValue; 35 } 36 }); 37 } 38 39 public Object getTarget() { 40 return target; 41 } 42 43 public void setTarget(Object target) { 44 this.target = target; 45 } 46 }
测试类
1 package com.shore.test; 2 3 import org.junit.Test; 4 5 import com.shore.dao.IUserDao; 6 import com.shore.dao.factory.ProxyFactory; 7 import com.shore.dao.impl.UserDao; 8 9 /** 10 * @author DSHORE/2019-10-28 11 * 12 */ 13 public class MyTest { 14 @Test 15 public void testDynamicProxy() { 16 // 目标 17 IUserDao target = new UserDao(); 18 // 代理 19 IUserDao userDaoProxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); 20 //System.out.println(userDaoProxy.getClass()); // 返回值:class $Proxy4 (com.sun.proxy.$Proxy4) 21 userDaoProxy.save(); 22 } 23 }
测试结果图:
2.3.1、Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
1、JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
2、CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
3、CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
2.3.2、 实例:
用到的jar包:junit-4.7.jar 和 spring-core-3.2.5.jar
1 package com.shore.dao; 2 3 /** 4 * @author DSHORE/2019-10-28 5 * 6 */ 7 public class UserDao{ 8 9 public void save() { 10 // System.out.println("开启事务......"); //这一步,交给代理来做 11 12 System.out.println("保存用户成功!"); // session.save(obj); 13 14 // System.out.println("提交事务......"); //这一步,交给代理来做 15 } 16 }
代理工厂类
1 package com.shore.dao.proxy; 2 3 import java.lang.reflect.Method; 4 5 import org.springframework.cglib.proxy.Enhancer; 6 import org.springframework.cglib.proxy.MethodInterceptor; 7 import org.springframework.cglib.proxy.MethodProxy; 8 9 /** 10 * @author DSHORE/2019-10-28 11 * 12 */ 13 public class ProxyFactory implements MethodInterceptor { 14 // 维护一个目标对象 15 private Object target; 16 17 public ProxyFactory(Object target) { 18 super(); 19 this.target = target; 20 } 21 22 // 给目标对象创建一个代理对象 23 public Object getProxyInstance() { 24 // 1、调用工具类 25 Enhancer enhancer = new Enhancer(); 26 // 2、设置父类 27 enhancer.setSuperclass(target.getClass()); 28 // 3、设置回调函数,执行target方法的时候,触发拦截器intercept方法 29 enhancer.setCallback(this); 30 return enhancer.create(); 31 } 32 33 @Override 34 public Object intercept(Object object, Method method, Object[] objects, 35 MethodProxy proxy) throws Throwable { 36 System.out.println("开启事务-------"); 37 38 Object returnValue = method.invoke(target, objects); //放行 39 40 System.out.println("提交事务-------"); 41 return returnValue; 42 } 43 44 public Object getTarget() { 45 return target; 46 } 47 48 public void setTarget(Object target) { 49 this.target = target; 50 } 51 }
测试类:
1 package com.shore.test; 2 3 import org.junit.Test; 4 5 import com.shore.dao.UserDao; 6 import com.shore.dao.proxy.ProxyFactory; 7 8 /** 9 * @author DSHORE/2019-10-28 10 * 11 */ 12 public class MyTest { 13 @Test 14 public void testCglibProxy() { 15 //目标 16 UserDao target = new UserDao(); 17 //代理 18 UserDao userDaoProxy = (UserDao) new ProxyFactory(target).getProxyInstance(); 19 /** 20 * JAVA定义class,英文字符中仅支持 $ 和 _ 21 */ 22 //System.out.println(userDaoProxy.getClass()); //返回值:class com.shore.dao.UserDao$$EnhancerByCGLIB$$1543b6de 23 userDaoProxy.save(); 24 } 25 }
测试结果图:
注意:
总结:虽然三种工厂模式都能实现一样的效果,但,静态工厂代理模式不推荐使用,如果,需要代理的类很多,就会很麻烦。
原创作者:DSHORE 作者主页:http://www.cnblogs.com/dshore123/ 原文出自:https://www.cnblogs.com/dshore123/p/11753623.html 欢迎转载,转载务必说明出处。(如果本文对您有帮助,可以点击一下右下角的 推荐,或评论,谢谢!) |