-
介绍
什么是代理模式:给某一个对象提供一个代理,并且由代理对象控制对原对象的引用。
代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
代理模式包含如下角色:
ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。
RealSubject:真实主题角色,是实现抽象主题接口的类。
Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
-
实现
- 静态代理
静态代理由我们自己去生成的固定的代码进行编译。需要定义接口或者抽象的父类作为抽象目标类,具体目标类和代理类一起实现相同的接口或者是继承相同的类,然后通过调用相同的方法来调用目标对象的方法。
因为代理对象需要与目标对象实现一样的接口,所以会有很多的代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。解决此缺点的方法就是可以使用动态代理方式。
public static <T> void main(String[] args) {
// 静态代理
ProxyInterface proxyBase = new ProxyHandler(new ProxyMain());
proxyBase.request();
}
public class ProxyHandler implements ProxyInterface {
// 目标对象
private ProxyInterface proxy;
/**
* 构造方法
*
* @param ProxyInterface
* 目标对象
*/
public ProxyHandler(ProxyInterface proxy) {
this.proxy = proxy;
}
@Override
public void request() {
System.out.println("事物开始");
proxy.request();
System.out.println("事物结束");
}
}
- 动态代理
public interface ProxyInterface {
void request();
}
public class ProxyMain implements ProxyInterface {
@Override
public void request() {
System.out.println("request");
}
}
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
/**
* 构造方法
*
* @param target
* 目标对象
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("1111111111111");
Object result = null;
System.out.println("事物开始");
result = method.invoke(target, args);
System.out.println("事物结束");
return result;
}
}
public static <T> void main(String[] args) {
// jdk 动态代理实现
ProxyInterface proxy = (ProxyInterface) java.lang.reflect.Proxy
.newProxyInstance(ProxyMain.class.getClassLoader(),
ProxyMain.class.getInterfaces(),
new MyInvocationHandler(new ProxyMain()));
proxy.request();
}
- cglib动态代理
jdk动态代理要求被代理的目标对象必须是接口,cglib动态代理,也叫子类代理,它是在内存中创建一个子类对象来实现对目标类功能的扩展。CGLIB代理会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理,如前置处理和后置处理。在CGLIB底层,其实是借助了ASM这个强大的java字节码生成框架。
引入cglib依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.4</version>
</dependency>
被代理类:
/**
* Hello class
*
* @author guanhuifang
* @date 2018/2/25 上午11:52
**/public class Hello {
public void sayHello() {
System.out.println("Hello World!");
}
}
实现MethodInterceptor接口生成方法拦截器
/**
* HelloMethodInterceptor class
*
* @author guanhuifang
* @date 2018/2/25 上午11:55
**/public class HelloMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("之前"+method.getName());
methodProxy.invokeSuper(o,objects);
System.out.println("之后"+method.getName());
return null;
}
}
客户端验证:
/**
* Client class
*
* @author guanhuifang
* @date 2018/2/25 上午11:59
**/public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Hello.class); //继承被代理类
enhancer.setCallback(new HelloMethodInterceptor()); //设置回调
Hello hello = (Hello) enhancer.create(); //生成代理类对象
hello.sayHello();
}
}
运行结果:
之前sayHello
Hello World!
之后sayHello
Process finished with exit code 0
在enhance.create()创建完代理类对象之后,在代理类调用方法中会被我们实现的方法拦截器HelloMethodInterceptor拦截。如果被代理类hello被final修饰,则hello类不能被继承,即不能被代理。同样,如果被代理类hello类存在final修饰的方法,那么该方法不能被代理。
-
总结(使用场景)
客户端在使用一个功能时,不希望直接使用其接口,而是希望通过一个代理去完成其功能。类似于现实生活中,人们买、租房时常常会通过中介代理,由中介帮客户相关事项,而且代理常常可以为用户完成一些相关性工作,例如办理手续等。
AOP
日志
权限