概述
在调用者和目标对象之间增加一个中介角色
调用者->中介商->目标对象
生活中介
租客->房屋中介->房东
求职者->招聘网站->公司
适龄男青年->媒婆->适龄女青年
为什么需要中间商转差价
1专业的人干专业的事情,被代理人只关注自己能力范围的事情
2 信息垄断隔绝,jar没有源码 需要对原来方法增强
代理三要素
- 有共同的行为(方法) - 接口
- 目标对象(被代理人) - 实现行为
- 代理对象(代理人) - 实现行为 增强目标对象行为
设计原则
代理模式的两个设计原则:
- 代理类与委托类具有相似的行为(方法)
- 代理类增强委托类的行为,核心业务被代理人做,非核心业务公共业务代理人做
代理模式
静态代理
创建删除用户接口
public interface UserServer {/*** 删除用户* @param userId*/void deleteUser(Integer userId);}
创建目标对象
public class UserServerImpl implements UserServer {@Overridepublic void deleteUser(Integer userId) {System.out.println("删除用户"+userId);}}
创建代理对象
public class UserServerProxy implements UserServer{private UserServer userServer;public UserServerProxy(UserServer userServer) {this.userServer = userServer;}@Overridepublic void deleteUser(Integer userId) {System.out.println("开始事物");userServer.deleteUser(userId);System.out.println("提交事物");}}
测试验证
public class UserApp {public static void main(String[] args) {// 目标对象UserServerImpl userTarget = new UserServerImpl();//代理对象,把目标对象传给代理对象,建立代理关系UserServerProxy proxy = new UserServerProxy(userTarget);//执行代理方法proxy.deleteUser(1);}}
动态代理
Proxy类
调用它的newInstance方法可以生成某个对象的代理对象,该方法需要三个参数:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) {Objects.requireNonNull(h);final Class<?> caller = System.getSecurityManager() == null? null: Reflection.getCallerClass();/** Look up or generate the designated proxy class and its constructor.*/Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);return newProxyInstance(caller, cons, h);}
- ClassLoader loader:生成代理对象使用哪个类装载器【一般我们使用的是被代理类的装载器】
- Class<?>[] interfaces:生成哪个对象的代理对象,通过接口指定【指定要被代理类的接口】
- InvocationHandler h:生成的代理对象的方法里干什么事【实现handler接口,我们想怎么实现就怎么实现
InvocationHandler接口
/*** proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0* method:我们所要调用某个对象真实的方法的Method对象* args:指代代理对象方法传递的参数*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
事务代理类
public class TransactionProxy {private Object target;public TransactionProxy(Object target) {this.target = target;}public Object getProxyInstance() {return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),(Object object, Method method, Object[] args)->{System.out.println("开始事务");//执行目标对象方法Object returnValue = method.invoke(target, args);System.out.println("提交事务");return returnValue;});}}
验证动态代理
public class UserDynamicProxy {public static void main(String[] args) {UserServer target = new UserServerImpl();System.out.println(target.getClass());// 给目标对象,创建代理对象UserServer proxy = (UserServer) new TransactionProxy(target).getProxyInstance();// class $Proxy0 内存中动态生成的代理对象System.out.println(proxy.getClass());// 执行代理对象方法proxy.deleteUser(1);}}
代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理.
Cglib
静态代理和动态代理模式都是要求目标对象是实现一个接口,但是目标对象并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。
Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
<!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>
创建Cglib代理类
public class CglibProxy implements MethodInterceptor {private Object target;public CglibProxy(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();}@Overridepublic 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;}}
验证
public class UserCglibProxy {public static void main(String[] args) {UserServer userServer = new UserServerImpl();CglibProxy cglibProxy = new CglibProxy(userServer);UserServer proxyInstance = (UserServer)cglibProxy.getProxyInstance();proxyInstance.deleteUser(2);}}
