概述
在调用者和目标对象之间增加一个中介角色
调用者->中介商->目标对象
生活中介
租客->房屋中介->房东
求职者->招聘网站->公司
适龄男青年->媒婆->适龄女青年
为什么需要中间商转差价
1专业的人干专业的事情,被代理人只关注自己能力范围的事情
2 信息垄断隔绝,jar没有源码 需要对原来方法增强
代理三要素
- 有共同的行为(方法) - 接口
- 目标对象(被代理人) - 实现行为
- 代理对象(代理人) - 实现行为 增强目标对象行为
设计原则
代理模式的两个设计原则:
- 代理类与委托类具有相似的行为(方法)
- 代理类增强委托类的行为,核心业务被代理人做,非核心业务公共业务代理人做
代理模式
静态代理
创建删除用户接口
public interface UserServer {
/**
* 删除用户
* @param userId
*/
void deleteUser(Integer userId);
}
创建目标对象
public class UserServerImpl implements UserServer {
@Override
public void deleteUser(Integer userId) {
System.out.println("删除用户"+userId);
}
}
创建代理对象
public class UserServerProxy implements UserServer{
private UserServer userServer;
public UserServerProxy(UserServer userServer) {
this.userServer = userServer;
}
@Override
public 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();
}
@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;
}
}
验证
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);
}
}