原文:https://www.cnblogs.com/cenyu/p/6289209.html
代理商(Proxy)是一种设计模式,通过代理商对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能。
举个例子来说明:如果说我现在想买一辆二手车,最便捷的方法肯定是我去找中介,他们来给我做琐碎的事情,我只是负责选择自己喜欢的车,而后付钱即可以了。
代理商对象是对目标对象的扩展,并会调用目标对象
public interface IUserDao { void save(); }
public class UserDao implements IUserDao { @Override public void save() { System.out.println("----已经保存数据!----"); }}
public class UserDaoProxy implements IUserDao { //目标对象 private IUserDao target; public UserDaoProxy(IUserDao target){ this.target=target; } @Override public void save() { System.out.println("开始事务..."); target.save();//执行目标对象的方法 System.out.println("提交事务..."); }}
@Test public void staticProxy() { //目标对象 UserDao target = new UserDao(); //代理商对象,建立代理商关系 UserDaoProxy proxy = new UserDaoProxy(target); proxy.save();//执行的是代理商的方法 }
静态代理商的缺点:接口新添加方法时,类过多时,需要手动维护,过于繁琐,但是通过动态代理商机制可以处理这一问题。
spring 中 AOP 通过 动态代理商 在运行时为我们的代码加强,例如我们在开发的时候只要要做业务逻辑,AOP 通过动态代理商可以为我们做事务,日志管理,权限校验等等。
我们不需要再去手动创立代理商类(但是要求被代理商类必需实现一个接口),只要要做一个动态代理商工厂就可,jdk通过反射为我们在内存中动态创立代理商对象,以及在方法执行的前后增加通知。
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 创立动态代理商对象 * */public class JdkProxyFactory{ //维护一个目标对象 private Object target; public JdkProxyFactory(Object target){ this.target=target; } //给目标对象生成代理商对象 public Object getProxyInstance(){ return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始事务2"); //执行目标对象方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务2"); return returnValue; } } ); }}
@Test public void jdkProxy() { // 目标对象 IUserDao target = new UserDao(); // 原始类型 System.out.println("原始类型" + target.getClass()); // 给目标对象,创立代理商对象 IUserDao proxy = (IUserDao) new JdkProxyFactory(target).getProxyInstance(); // class $Proxy0 内存中动态生成的代理商对象 System.out.println("动态代理商后对象类型:" + proxy.getClass()); // 代理商对象 执行方法 proxy.save(); }
执行测试方法
原始类型class com.example.demo.original_code.UserDao动态代理商后对象类型:class com.sun.proxy.$Proxy4开始事务2----已经保存数据!----提交事务2
静态代理商 和 jdk代理商 要求目标对象必需实现接口,而 cglib 动态代理商无需实现接口。
cglib 会动态为目标对象 创立一个子类对象。
使用须知:
1.被代理商的类不能为 final
2.被代理商类的方法 不能为 final/static,否则无法被阻拦
import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;/** * Cglib子类代理商工厂 * 对UserDao在内存中动态构建一个子类对象 */public class CglibProxyFactory implements MethodInterceptor { //维护目标对象 private Object target; public CglibProxyFactory(Object target) { this.target = target; } //给目标对象创立一个代理商对象 public Object getProxyInstance(){ //1.工具类 Enhancer en = new Enhancer(); //2.设置父类 en.setSuperclass(target.getClass()); //3.设置回调函数 en.setCallback(this); //4.创立子类(代理商对象) return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开始事务..."); //执行目标对象的方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务..."); return returnValue; }}
@Test public void cglibProxy() { //目标对象 UserDao target = new UserDao(); //代理商对象 UserDao proxy = (UserDao) new CglibProxyFactory(target).getProxyInstance(); //执行代理商对象的方法 proxy.save(); }