代理模式主要是为对象提供一种代理以控制对这个对象的访问,主要解决一些直接访问对象时带来的问题,比如消息的预处理、消息过滤、消息后置处理等。代理类本身不提供具体服务,而是通过调用被代理类中的方法来提供服务
静态代理与动态代理的区别:
- 静态代理:由程序员编写源代码,对其进行编译,在程序运行前,代理类的.class文件就已经存在了
- 动态代理:在程序运行时,运用反射机制动态创建而成,无需程序员手工编写它的源代码
静态代理
创建一个Subject接口,并添加被代理类RealSubject实现Subject接口,再创建一个代理类Proxy,也实现这个接口,并持有这个被代理对象;可以在代理类中编写对应的预处理/后置处理方法。
Subject接口
public interface Subject {
void request();
}
被代理对象RealSubject
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("访问request方法");
}
}
静态代理类Proxy
public class Proxy implements Subject {
private RealSubject realSubject = new RealSubject();
@Override
public void request() {
this.before();
realSubject.request();
this.after();
}
private void before(){
System.out.println("before request");
}
private void after(){
System.out.println("after request");
}
}
测试类
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy();
subject.request();
}
}
测试结果
before request
访问request方法
after request
可以看到调用request()方法前后调用了代理类的预处理方法和后置处理方法,实现了代理模式的功能,存在的问题就是每个代理类都需要编写独立的代码,比较繁琐。
动态代理
动态代理有两种,JDK动态代理和Cglib动态代理,Spring使用了这两种动态代理方式,如果目标对象实现了接口,默认情况下会采用JDK动态代理来实现,两者的区别如下:
- JDK动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
- Cglib动态代理:利用asm开源包,代理对象类的class文件加载进来后通过修改其字节码生成子类来处理
JDK动态代理
为了更好的显示静态代理、JDK动态代理、Cglib动态代理的区别,Subject和RealSubject均使用同样的类
Subject接口
public interface Subject {
void request();
}
被代理对象RealSubject
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("访问request方法");
}
}
JDK动态代理类JdkProxyHandler,实现InvocationHandler
public class JdkProxyHandler implements InvocationHandler {
//被代理的对象
private Object object;
public JdkProxyHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.before();
method.invoke(object, args);
this.after();
return null;
}
private void before(){
System.out.println("before request");
}
private void after(){
System.out.println("after request");
}
}
测试类
public class JdkClient {
public static void main(String[] args) {
Subject subject = new RealSubject();
InvocationHandler invocationHandler = new JdkProxyHandler(subject);
//通过Proxy类的静态方法newProxyInstance返回一个接口的代理实例,方法第二个参数限制了必须有接口才能使用JDK动态代理
Subject proxy = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), invocationHandler);
proxy.request();
}
}
测试结果
before request
访问request方法
after request
Cglib动态代理
Cglib动态代理利用asm开源包,需要引入以下依赖,Subject和RealSubject使用同样的类
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
</dependency>
Cglib动态代理类CglibProxy,实现MethodInterceptor
public class CglibProxy implements MethodInterceptor {
/**
* 生成代理类(被代理类的子类)
* @param clazz
* @return
*/
public Object createProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
this.before();
//调用被代理类(父类)具体业务方法
methodProxy.invokeSuper(o, objects);
this.after();
return null;
}
private void before(){
System.out.println("before request");
}
private void after(){
System.out.println("after request");
}
}
测试类
public class CglibClient {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
RealSubject proxy = (RealSubject) cglibProxy.createProxy(RealSubject.class);
proxy.request();
}
}
测试结果
before request
访问request方法
after request
不管是使用JDK动态代理还是Cglib动态代理,都能达到同样的效果,比起静态代理需要给每个代理类编写代码来说动态代理更加灵活。