代理模式主要作用是不改变原始类的情况下,通过代理类来访问原始类方法,从而对原始类方法进行增强。当然,把增强功能直接放入原始类也是可以的,但是这样不符合开闭原则,而且容易把业务代码和非业务代码耦合。代理模式的实现有2种方式
1.代理类和原始类实现同一个接口,代码如下:
public interface UserManager { //新增用户抽象方法 void addUser(String userName, String password); //删除用户抽象方法 void delUser(String userName); } public class UserManagerImpl implements UserManager{ @Override public void addUser(String userName, String password) { System.out.println("传入参数为 userName: "+userName+" password: "+password); } @Override public void delUser(String userName) { System.out.println("传入参数为 userName: "+userName); } } public class UserManagerProxy implements UserManager{ private UserManager userManager = new UserManagerImpl(); @Override public void addUser(String userName, String password) { System.out.println("proxy addUser"); userManager.addUser("zhangsan", "123456"); } @Override public void delUser(String userName) { System.out.println("proxy deleteUser"); userManager.delUser("zhangsan"); } }
先定义了一个UserManager接口, UserManagerImpl实现了这个接口,做具体的操作。同时,UserManagerProxy也实现了这个接口,但是UserManagerProxy自己不做具体的业务,而是组合了UserManagerImpl,用UserManagerImpl来做业务操作。UserManagerProxy自身做一些增强操作,比如记录日志等。
2.如果原始类没有实现接口,这种情况下代理模式就得用继承的方式来实现了。如下代码:
public class UserManagerProxy1 extends UserManagerImpl{ @Override public void addUser(String userName, String password) { System.out.println("proxy addUser"); super.addUser("zhangsan", "123456"); } @Override public void delUser(String userName) { System.out.println("proxy deleteUser"); super.delUser("zhangsan"); } }
上面的都是静态代理,静态代理的问题是针对每一个被代理类都需要生成一个代理类,而且代理类里面需要重新实现被代理类的那一套代码逻辑。使用动态代理可以解决这个问题,下面我们看一下动态代理的实现。
3.jdk中的动态代理
public class JdkProxy implements InvocationHandler{ private Object target ;//需要代理的目标对象 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理,监听开始!"); Object result = method.invoke(target, args); System.out.println("JDK动态代理,监听结束!"); return result; } //定义获取代理对象方法 private Object getJDKProxy(Object targetObject){ //为目标对象target赋值 this.target = targetObject; //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } public static void main(String[] args) { JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象 UserManager user = (UserManager) jdkProxy.getJDKProxy(new UserManagerImpl());//获取代理对象 user.addUser("admin", "123123");//执行新增方法 } }
jdk只能对实现了接口的类做代理,下面看一下cglib代理
4.cglib代理
cglib代理是基于代理类生成了一个子类,就像上面2的实现一样,代码如下:
public class CglibProxy implements MethodInterceptor { private Object target;//需要代理的目标对象 //重写拦截方法 @Override public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态代理,监听开始!"); Object invoke = method.invoke(target, arr);//方法执行,参数:target 目标对象 arr参数数组 System.out.println("Cglib动态代理,监听结束!"); return invoke; } //定义获取代理对象方法 public Object getCglibProxy(Object objectTarget){ //为目标对象target赋值 this.target = objectTarget; Enhancer enhancer = new Enhancer(); //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类 enhancer.setSuperclass(objectTarget.getClass()); enhancer.setCallback(this);// 设置回调 Object result = enhancer.create();//创建并返回代理对象 return result; } public static void main(String[] args) { CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象 UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象 user.delUser("admin");//执行删除方法 } }
5.动态代理的使用
动态代理的使用场景非常广泛,在我们日常开发中,spring的事务管理就是用动态代理实现的。除此之外,比如对于缓存,我们可以在代理类中查询缓存,而在被代理类中查询数据库,代理类只有缓存中没有数据时,才会访问数据库。再比如RPC框架,我们可以通过代理类将缓存细节隐藏起来,只关注调用。
个人公众号,欢迎关注,共同学习进步