1.定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
1.1组成
抽象角色(ISubject):通过接口或抽象类声明真实角色实现的业务方法。
代理角色(SubjectProxy):实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色(ConcreteSubject):实现抽象角色(被代理对象),定义真实角色所要实现的业务逻辑,供代理角色调用。
类图结构基本如下:
2.分类
java中代理模式的分类主要分为以下三种
静态代理:程序员自己编写代理类;
基于接口的动态代理:jdk根据字节码在程序运行时生成代理对象,要求代理对象和被代理对象实现 了同一接口;
基于类的动态代理:第三方字节码工具CGLib,在程序运行时生成代理对象,代理对象是属于被代理对象的子类,若被代理对象是final类型的则无法实现代理功能
3.实现
3.1静态代理
3.1.1定义抽象角色ISubject
public interface ISubject {
void action();
}
3.1.2定义具体角色ConcreteSubject
public class ConcreteSubject implements ISubject {
@Override
public void action() {
System.out.println("Do acion in subject");
}
}
3.1.3定义代理角色SubjectProxy
public class SubjectProxy implements ISubject {
private ISubject target;
SubjectProxy(ISubject target){
this.target = target;
}
@Override
public void action() {
preAction();
target.action();
postAction();
}
private void preAction() {
System.out.println("pre Action");
}
private void postAction() {
System.out.println("post Action");
}
}
3.1.4客户端测试
public class Client {
public static void main(String[] args) {
ISubject target = new ConcreteSubject();
SubjectProxy subjectProxy = new SubjectProxy(target);
subjectProxy.action();
}
}
分析:代理类和被代理类是通过组合的方式相互协作,代理类持有被代理对象,在执行被代理对象的具体业务之前或之后通过插入对应的处理逻辑来控制对被代理对象业务方法的访问过程.
3.2基于接口的动态代理(JDK代理)
3.2.1定义抽象角色ISubject
public interface ISubject {
void action1();
void action2();
}
3.2.2定义具体角色ConcreteSubject
public class ConcreteSubject implements ISubject {
@Override
public void action1() {
System.out.println("Do acion1 in subject");
}
@Override
public void action2() {
System.out.println("Do acion2 in subject");
}
}
3.2.3定义代理角色SubjectProxy
该代理类由JDK自动生成,代码块如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
Proxy.newProxyInstance方法的三个参数含义:
第一个参数:ClassLoader loader 指定当前目标对象使用类加载器
第二个参数:Class interfaces 目标对象实现的接口的类型
第三个参数:InvocationHandler h 事件处理器 ,也就是在调用目标方法时需要执行的业务逻辑是什么.
事件处理器
public class MethodHandler implements InvocationHandler {
private ISubject target;
MethodHandler(ISubject target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" Interfaace pre " + method.getName());
Object returnValue = method.invoke(target, args);
System.out.println(" Interfaace post " + method.getName());
return returnValue;
}
}
3.2.4客户端测试
public class Client {
public static void main(String[] args) {
//目标对象(被代理对象)
ISubject target = new ConcreteSubject();
//调用目标对象方法时,会通过该处理中的invoke来间接调用目标方法
MethodHandler methodHandler = new MethodHandler(target);
//通过jdk动态代理获得代理对象
ISubject interfaceProxy = (ISubject)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
methodHandler);
interfaceProxy.action1();
}
}
调用interfaceProxy.action1()会执行MethodHandler(我们定义的处理器)的invoke方法,在该方法中可以对被代理对象业务调用的处理逻辑进行自定义(调用之前和调用之后等等处理操作).
3.3基于类的动态代理(CGLib代理)
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
3.3.1定义抽象角色ISubject
基于类的动态代理的动态代理,不需要定义抽象角色
3.3.2定义具体角色ConcreteSubject
public class ConcreteSubject {
public void action() {
System.out.println("Do acion in subject");
}
}
3.3.3定义代理角色SubjectProxy
该代理对象由CGLIB基于类来自动生成的,其核心逻辑代码如下:
//cglib动态代理工具类
Enhancer enhancer = new Enhancer();
//指定(目标对象)被代理对象,以便通过该对象生成子类(代理对象)
enhancer.setSuperclass(ConcreteSubject.class);
//在(目标对象)被代理对象的业务方法被调用时,的回调方法,类似于JDK中的invoke方法的作用
enhancer.setCallback(new MyMethodInterceptor());
//CGLIB基于类生成代理对象
ConcreteSubject proxy = (ConcreteSubject)enhancer.create();
其中回调处理类定义:
public class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(" pre Acion");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println(" post Acion");
return null;
}
}
3.3.4客户端测试
public class Client {
public static void main(String[] args) {
//cglib动态代理工具类
Enhancer enhancer = new Enhancer();
//指定(目标对象)被代理对象,以便通过该对象生成子类(代理对象)
enhancer.setSuperclass(ConcreteSubject.class);
//在(目标对象)被代理对象的业务方法被调用时,的回调方法,类似于JDK中的invoke方法的作用
enhancer.setCallback(new MyMethodInterceptor());
//CGLIB基于类生成代理对象
ConcreteSubject proxy = (ConcreteSubject)enhancer.create();
//执行业务逻辑
proxy.action();
}
}
4.总结
代理模式的本质:将目标对象的访问过程(方法调用)交由代理对象处理(何时调用,如何调用)
Spring中AOP的核心就是基于JDK动态代理和基于CGLIb的动态代理模式