概述
由于某些原因需要给某对象提供一个代理以控制该对象的访问。这时访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
Java中的代理按照代理类生成时机不同分为静态代理和动态代理。静态代理是在编译时期就生成,而动态代理类则是在java运行时虚拟机内部自动生成。动态代理又有jdk代理和cglib代理两种
结构/角色
代理模式分为三种角色:
- 抽象主题类:通过接口和抽象类声明真实主题和代理对象实现的业务方法
- 真实主题类:实现了抽象主题的具体业务方法,是代理对象所要代表的真实对象(被代理对象/目标对象),是最终要引用的对象。
- 代理类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或者扩展真是主题的功能。
静态代理实现
1.抽象主题
public interface UserService {
void update();
void delete();
void insert();
}
2.真实主题类
public class UserServiceImpl implements UserService {
@Override
public void update() {
System.out.println("修改数据业务。。。");
}
@Override
public void delete() {
System.out.println("删除数据业务。。。");
}
@Override
public void insert() {
System.out.println("增加数据业务。。。");
}
}
3.代理类
public class UserProxy implements UserService {
//抽象主题的引用
private UserService userService;
public UserProxy(UserService userService) {
this.userService = userService;
}
//扩展真实主题的功能
@Override
public void update() {
System.out.println("增强代码");
userService.update();
}
@Override
public void delete() {
System.out.println("增强代码");
userService.delete();
}
@Override
public void insert() {
System.out.println("增强代码");
userService.insert();
}
}
动态代理(JDK)
Java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象(也实现了抽象主题)。
1.抽象主题
public interface OrderService {
int update();
void delete();
void insert();
}
2.真实主题类
public class OrderServiceImpl implements OrderService{
@Override
public int update() {
System.out.println("update业务处理中...");
return 10;
}
@Override
public void delete() {
System.out.println("delete业务处理中...");
}
@Override
public void insert() {
System.out.println("insert业务处理中...");
}
}
3.InvocationHandler的实现类(后面会将该类的作用)
public class TimerInvocationHandler implements InvocationHandler {
private Object orderService;
public TimerInvocationHandler() {}
public TimerInvocationHandler(Object orderService) {
this.orderService = orderService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行invoke方法");
System.out.println("增强代码1");
Object invoke = method.invoke(orderService, args);//相当于调用真实主题类方法
System.out.println("增强代码2");
System.out.println("=============");
return invoke;
}
}
4.测试类
public class Client{
public static void main(String[] args){
//创建目标类对象或者真实主题类
OrderService orderService = new OrderServiceImpl();
//创建代理对象,虚拟机内部自动生成一个代理类,该类是实现了抽象主题接口的
OrderService proxyInstance =(OrderService)Proxy.newProxyInstance(orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(),
new TimerInvocationHandler(orderService))
}
}
//解释:newProxyInstance方法三个参数:
// arg1:类加载器,用于加载代理类,使用真实对象的类加载器即可
// arg2: 真实对象所实现的接口,即代理模式真实对象和代理对象实现相同的接口
// arg3: 代理对象的调用处理程序(而参数本身是一个接口类型,因此要自定义一个类(TimerInvocationHandler)来实现它
总结:jdk动态代理其实和动态代理产不多,区别只是一个手动的创建代理类,一个是程序运行时虚拟机自动给创建了代理类(它是通过Proxy的方法和其参数来确定构造代理类的),同时也帮代理类也实现类抽象主题接口。jdk动态代理只能代理接口,意思是必须有抽象主题接口,否则无法代理。而cglib恰好对其进行了补充,它为没有实现接口的类提供代理。
备注:spring的aop原理默认是基于jdk动态代理的,可以选择使用cglib