代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
静态代理
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理着你是角色,代理真实角色后,我们一般会做一些复数操作
- 客户:访问代理对象的人
以租房举例:
【抽象角色】
public interface Rent {
public void rent();
}
【真实角色】
public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要租房子了");
}
}
【代理角色】
public class Agent implements Rent{
private Host host;
public Agent(Host host) {
this.host = host;
}
public void seeHouse(){
System.out.println("中介带你看房");
}
public void fare(){
System.out.println("收中介费");
}
@Override
public void rent() {
host.rent();
}
}
【客户】
public class Client {
public static void main(String[] args) {
Host host = new Host();
Agent proxy = new Agent(host);
proxy.seeHouse();
proxy.rent();
proxy.fare();
}
}
输出结果:
中介带你看房
房东要租房子了
收中介费
代理模式的优点:
- 可以使真实角色的操作哦更加纯粹,不用去关注一些公共的业务
- 公共业务就交给代理角色,实现了业务的分工
- 公共业务扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量会翻倍
动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的,不是我们直接写好的
- 动态代理分两大类:基于接口的动态代理 和 基于类的动态代理
- 基于接口:JDK 动态代理
- 基于类:cglib
- java 字节码实现:javasist
还是以租房为例:
JDK 动态代理
需要了解两个类:Proxy
和 InvocationHandler
【代理角色】
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
// 动态生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
@Override
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理中介带你看房");
Object result = method.invoke(rent, args);
System.out.println("收中介费");
return result;
}
}
【客户】
public class Client2 {
public static void main(String[] args) {
// 真实角色
Host host = new Host();
// 代理角色:现在还没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
// 通过调用程序处理角色来处理我们要调用的接口对象
pih.setRent(host);
// 生成代理类实例,即代理对象
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
通用动态代理处理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyHandler implements InvocationHandler {
// 被动态代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 动态生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
// 处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// before call method do something
Object result = method.invoke(target, args);
// after call method do something
return result;
}
}
CGLib 动态代理
CGLib 采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK 动态代理与 CGLib 动态代理均是实现 Spring AOP 的基础。
【jar包】
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
【代理类】
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (method.getName().equals("rent")) {
System.out.println("代理中介带你看房");
methodProxy.invokeSuper(o, args);
System.out.println("收中介费");
}
return null;
}
public Object getInstance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Host.class); // 这里不需要搞个接口了,cglib支持基于类的动态代理
enhancer.setCallback(this);
return enhancer.create();
}
}
【客户】
public class Client3 {
public static void main(String[] args) {
CGLibDynamicProxy proxy = new CGLibDynamicProxy();
Rent rent = (Rent) proxy.getInstance();
rent.rent();
}
}