版权声明:本博客为博主原创,欢迎大佬批评指点! https://blog.csdn.net/qq_31332467/article/details/84400774
代理模式
一直没有去了解过代理模式。该文章也是我从网上找到的一些资料整理的,方便我自己日后自己查询使用。
静态代理
静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。
/**方式一:聚合式静态代理
* @author Goser (mailto:[email protected])
* @Since 2016年9月7日
*/
//1.抽象主题接口
public interface Manager {
void doSomething();
}
//2.真实主题类
public class Admin implements Manager {
public void doSomething() {
System.out.println("Admin do something.");
}
}
//3.以聚合方式实现的代理主题
public class AdminPoly implements Manager{
private Admin admin;
public AdminPoly(Admin admin) {
super();
this.admin = admin;
}
public void doSomething() {
System.out.println("Log:admin操作开始");
admin.doSomething();
System.out.println("Log:admin操作结束");
}
}
//4.测试代码
Admin admin = new Admin();
Manager m = new AdminPoly(admin);
m.doSomething();
//方式二:继承式静态代理
//与上面的方式仅代理类和测试代码不同
//1.代理类
public class AdminProxy extends Admin {
@Override
public void doSomething() {
System.out.println("Log:admin操作开始");
super.doSomething();
System.out.println("Log:admin操作开始");
}
}
//2.测试代码
AdminProxy proxy = new AdminProxy();
proxy.doSomething();
---------------------
聚合实现方式中代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活
动态代理
JDK动态代理步骤
- 创建一个实现InvocationHandler接口的类,它必须实现invoke()方法
- 创建被代理的类及接口
- 调用Proxy的静态方法,创建一个代理类
- 通过代理调用方法
//1. 抽象主题
public interface Moveable {
void move() throws Exception;
}
//2. 真实主题
public class Car implements Moveable {
public void move() throws Exception {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中…");
}
}
//3.事务处理器
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* 参数:
*proxy 被代理的对象
*method 被代理对象的方法
*args 方法的参数
* 返回:
*Object 方法返回值
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽车开始行驶…");
method.invoke(target, args);
long stopTime = System.currentTimeMillis();
System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");
return null;
}
}
//测试类
public class Test {
public static void main(String[] args) throws Exception{
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
/**
*loader 类加载器
*interfaces 实现接口
*h InvocationHandler
*/
Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
m.move();
}
}
---------------------
cglib动态代理
前面分析到,因为Java只允许单继承,而JDK生成的代理类本身就继承了Proxy类,因此,使用JDK实现的动态代理不能完成继承式的动态代理,但是我们可以使用cglib来实现继承式的动态代理。
大名鼎鼎的Spring中就含有cglib动态代理,在此也以Spring中自带的cglib完成动态代理的实现:
//1.具体主题
public class Train{
public void move(){
System.out.println("火车行驶中…");
}
}
//2.生成代理
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* 参数:
* obj目标实例对象
*method 目标方法的反射对象
* args方法的参数
* proxy代理类的实例
*/
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
//代理类调用父类的方法
System.out.println("日志开始");
proxy.invokeSuper(obj, args);
System.out.println("日志结束");
return null;
}
}
//3.测试
public class Test {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Train t = (Train) proxy.getProxy(Train.class);
t.move();
}
}
---------------------
结论
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理。在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理。Proxy 很美很强大,但是仅支持 interface 代理。Java 的单继承机制注定了这些动态代理类们无法实现对 class 的动态代理。好在有cglib为Proxy提供了弥补。class与interface的区别本来就模糊,在java8中更是增加了一些新特性,使得interface越来越接近class,当有一日,java突破了单继承的限制,动态代理将会更加强大。