代理模式核心作用就是通过代理对象实现对核心对象使用的控制
设计思路:定义一个抽象角色,让代理角色和真实角色分别去实现它
真实角色—实现抽象角色,定义核心业务逻辑,供代理角色调用。它只关注核心业务逻辑,比如具体的计算逻辑
代理角色—实现抽象角色,是真实角色的代理,通过调用真实角色的业务逻辑方法,实现对真实角色访问的控制,比如报文中的一些格式化内容
代理模式分为静态代理和动态代理两种,静态代理是我们自己编写代理类,动态代理是程序运行中动态产生代理类
静态代理实现代码
// 定义抽象角色
public interface IStar {
void confer();
void signContract();
void bookingTicket();
void sing();
void collectMoney();
}
// 定义真实角色
public class RealStar implements IStar{
@Override
public void confer() {
System.out.println("realStar confer...");
}
@Override
public void signContract() {
System.out.println("realStar signContract...");
}
@Override
public void bookingTicket() {
System.out.println("realStar bookingTicket...");
}
@Override
public void sing() {
System.out.println("realStar sing...");
}
@Override
public void collectMoney() {
System.out.println("realStar collectMoney...");
}
}
// 定义代理角色,代理角色持有真实角色,并在核心业务方法处调用真实角色的核心方法
public class ProxyStar implements IStar{
RealStar realStar = new RealStar();
@Override
public void confer() {
System.out.println("proxyStar confer...");
}
@Override
public void signContract() {
System.out.println("proxyStar signContract...");
}
@Override
public void bookingTicket() {
System.out.println("proxyStar bookingTicket...");
}
@Override
public void sing() {
realStar.sing();
}
@Override
public void collectMoney() {
System.out.println("proxyStar collectMoney...");
}
}
静态代理需要定义接口并分别创建代理类和真实类,代理对象持有真实类的对象并在核心方法处调用真实对象的核心方法
动态代理一般有两种方式:JDK动态代理和CGLIB动态代理
JDK动态代理实现代码:
// 抽象角色
public interface IStar {
void sing();
}
// 真实角色
public class RealStar implements IStar{
@Override
public void sing() {
System.out.println("realStar singing...");
}
}
// 动态生成代理角色
public class StarHandler {
private IStar star;
public StarHandler(IStar star) {
this.star = star;
}
public Object getInstance(){
return Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), star.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置通知工作");
method.invoke(star,args);
System.out.println("后置通知工作");
return null;
}
});
}
}
从上面可以看出在 StarHandler
类中的 getInstance()
方法生成了代理类,方法中调用的 Proxy.newProxyInstance
有三个关键参数,第一个是获取类加载器,第二个是获取真是对象所实现的接口,第三个是一个匿名内部类通过反射实现了对真实对象的调用,并且可以在方法前后增加代码。因此也可以得出JDK动态代理的一个特点就是需要真实对象通过接口定义业务方法,也就是说无法摆脱接口的束缚
CGLIB动态代理实现代码:
// 真实角色
public class Star {
public void sing(){
System.out.println("realStar sing...");
}
}
// 可以生成代理类的handler
public class StarHandler implements MethodInterceptor {
private Object target;
public Object getInstance(final Object target) {
this.target = target;
// Enhancer类是CGLIB中的一个字节码增强器,它可以方便的对你想要处理的类进行扩展
Enhancer enhancer = new Enhancer();
// 将被代理的对象设置成父类
enhancer.setSuperclass(target.getClass());
// 回调方法,设置拦截器
enhancer.setCallback(this);
// 动态创建一个代理类
return enhancer.create();
}
// 设置拦截的回调方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("明星表演前置方法...");
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("明星表演后置方法...");
return obj;
}
}
CGLIB采用字节码技术,对于目标类无需实现接口,CGLIB会根据目标类动态生成他的子类作为代理,对应的方法会调用 StarHandler
中实现的 intercept()
方法来实现对真实角色的代理和增强,因为CGLIB是基于字节码技术动态生成子类的原理,所以CGLIB无法对 final
修饰的方法实现代理