jdk动态代理推荐看这篇文章
https://www.jianshu.com/p/4e1...
一.什么是代理模式
代理模式是设计模式中最常见的一种。当目标类不方便操作时,这时用另一个类代替目标类执行相同的操作。
意图:不改变原目标类的前提下,提供额外的功能,扩展目标对象的功能。
二.静态代理和动态代理
静态代理:编译期目标类,代理类,接口都已经生成class文件。
当我们要改变已有的代码时,有两种方式。1),直接在原始代码上修改,但是这种不符合扩展开放,修改关闭的原则。
2)增加代理类,通过静态代理即可实现。
3)比如要在原始的方法前后打印耗时日志,我们可以使用代理类实现这个功能。目标类和代理类实现相同的接口,在代理类中将目标类的对象作为属性,然后调用原来的方法。同时可以加入修改的代码。
//接口
public interface Image {
void display();
}
//代理类
public class ProxyImage implements Image {
private RealImage realImage;//目标类的对象
public ProxyImage(RealImage realImage) {
this.realImage = realImage;
}
@Override
public void display() {
long startTime = System.currentTimeMillis();
realImage.display();
long endTime = System.currentTimeMillis();
System.out.println("执行display方法耗时:"+(endTime-startTime));
}
}
//目标类
public class RealImage implements Image {
@Override
public void display() {
System.out.println("开始显示图片");
}
}
//测试 不改变原来的逻辑,又添加了新的功能
public class Test {
public static void main(String[] args) {
RealImage realImage = new RealImage();
ProxyImage proxyImage = new ProxyImage(realImage);
proxyImage.display();
}
}
动态代理:代理类在程序运行过程中被创建。动态代理的优势在于可以很方便的对目标类的函数进行统一的处理。而不是修改目标类中的每个方法。分为JDK动态代理和CGlib动态代理,
1)JDK动态代理:又称为基于接口的代理
java.lang.reflect.Proxy:生成动态代理对象;
java.lang.reflect.InvocationHandler 处理器接口;
(1)定义一个处理器类,实现invocationHandler接口,并重写invoke方法。
(2)代理类实现和目标类相同的接口//自动实现
(3)调用Proxy.newProxyInstance(...)生成一个代理实例。
(4)通过代理实例调用方法
//接口
public interface Subject {
int sellBooks();
}
//目标类
public class RealSubject implements Subject {
@Override
public int sellBooks() {
System.out.println("卖书");
return 1;
}
}
//自定义处理器,每一个代理类对象都对应一个处理器
public class MyInvocationHandler implements InvocationHandler {
Subject realSubject;
public MyInvocationHandler(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用代理类");
int count = (int)method.invoke(realSubject, args);//执行目标类的方法
System.out.println("调用的是卖书的方法");
return count;
}
}
//
public class Test{
public static void main(String[] args) {
Subject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
Class cls = realSubject.getClass();
Subject proxyClass = (Subject)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), myInvocationHandler);
proxyClass.sellBooks();
}
}
在测试类中通过Proxy类的静态方法获取代理类对象,其中三个参数,一个是类加载器(目标类),目标类实现的接口,处理器对象。程序运行过程中动态产生代理对象。当执行sellBooks方法时,实际会执行MyInvocationHandler中的invoke方法,通过反射执行目标类的方法。在执行目标方法前后,我们可以做一些处理,增强功能。
2)CGlib动态代理:目标类生成子类实现代理,子类执行方法时会被拦截器拦截,在拦截器中的interceptor方法中,通过反射执行目标方法,这样在目标方法前后我们可以做一些自定义的处理。 如果是private或者final修饰的方法,则不会被重写。
CGlib是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理。SpringAOP中默认使用jdk动态代理,如果目标对象没有实现接口,则使用cglib动态代理
public class Engineer {
//可以被代理
public void eat() {
System.out.println("工程师正在吃饭");
}
//不能被生成的子类重写
public final void work() {
System.out.println("工程师正在工作");
}
//不能被生成的子类重写
private void play() {
System.out.println("the engineer is playing game");
}
}
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理被调用");
Object result = method.invoke(target, objects);
return result;
}
public static Object getProxy(Object target) {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置拦截器
enhancer.setCallback(new CglibProxy(target));
//生成代理类对象
return enhancer.create();
}
}
public class TestCglib {
public static void main(String[] args) {
//获取代理类实例
Engineer proxyEngineer = (Engineer)CglibProxy.getProxy(new Engineer());
proxyEngineer.eat();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。