
代理类相当于是原本的类的class对象+自定义操作,理解为一层封装。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
假如一个班的同学要向老师交班费,但是都是通过班长把自己的钱转交给老师。这里,班长就是代理学生上交班费,班长就是学生的代理。
静态代理
由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
流程:
-
- 定义一个接口,定义了一个抽象方法。
- 被代理类实现了接口,重写了方法。
- 代理类也实现接口,然后将被代理类引用,并通过构造方法引入,然后重写方法,此时可以调用被代理类的方法
- main方法new了被代理类和代理类两个对象,前者作为参数传给后者,并调用后者的方法。
缺点:每个被代理类都要写一个针对的代理类。
动态代理
代理类在程序运行时创建的代理方式被成为动态代理。动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法
若目标对象实现了接口,spring默认使用「JDK的动态代理」。
-
- 优点:因为有接口,所以使系统更加松耦合;
- 缺点:为每一个目标类创建接口;
若目标对象没有实现任何接口,spring使用「CGLib动态代理」。
-
- 优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
- 缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
「1、jdk动态代理」
newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法。理解上述代码需要对Java反射机制有一定了解。动态代理神奇的地方就是:
-
- 代理对象是在程序运行时产生的,而不是编译期;
- 对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等;之后我们通过某种方式执行真正的方法体,可以通过反射调用对象的相应方法,还可以通过RPC调用远程方法。
使用方法:代理类实现「InvocationHandler」,然后引用被代理类,并在构造方法里传入。然后重写invoke方法,为具体操作代码。然后通过
Proxy.newProxyInstance( getClass().getClassLoader(), new Class<?>[] {Hello.class}, // 2. 代理需要实现的接口,可以有多个
new LogInvocationHandler(new HelloImp()));// 3. 方法调用的实际处理者
Java动态代理是基于接口的,没有实现接口该类无法使用JDK代理,CGLIB登场。
「2、CGLIB动态代理」
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法去技术拦截所有的父类方法的调用,并顺势织入横切逻辑。
目标对象:
//目标对象RealSubject,cglib不需要定义目标类的统一接口
public class RealSubject {
public void request() {
System.out.println("real subject execute request");
}
public void hello() {
System.out.println("hello");
}
}
代理对象:实现MethodInterceptor,重写intercept方法。
//代理对象
public class DemoMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before in cglib");
Object result = null;
try{
result = proxy.invokeSuper(obj, args);
}catch (Exception e){
System.out.println("get ex:"+e.getMessage());
throw e;
}finally {
System.out.println("after in cglib");
}
return result;
}
}
客户端调用:
//客户端
public class Client {
public static void main(String[] args){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new DemoMethodInterceptor());
// 此刻,realSubject不是单纯的目标类,而是增强过的目标类
RealSubject realSubject = (RealSubject) enhancer.create();
realSubject.hello();
realSubject.request()
}
}
也可以通过匿名的方式:
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before method run...");
Object result = proxy.invokeSuper(obj, args);
System.out.println("after method run...");
return result;
}
});
SampleClass sample = (SampleClass) enhancer.create();
sample.test();
}