带你用实例学习代理模式:静态代理、动态代理(JDK、CGlib)以及区别和优缺点

Spring AOP的核心技术就是动态代理,所以小编学习并整理了代理模式的材料,供大家一起学习。

1、代理模式满足的三个必要条件:

  • 两个角色:执行者、被代理对象
  • 这个过程必须要做,但是自己不能做或者不想做,交给专业的人(媒婆)
  • 执行者必须拿到被代理对象的引用(需要知道你要什么信息)
  •  

2、代理模式分:静态代理、动态代理(JDK动态代理和cglib动态代理)

3、静态代理:

a.定义一个接口

public interface Count(){

public void queryCount();

}

b.业务逻辑类实现接口

public class CountImpl implements Count(){

@Override

public void queryCount(){

System.out.println("实现业务逻辑类");

}

}

c.定义业务代理类

public class CountProxy implements Count(){

private CountImpl countImpl;

public CountProxy(CountImpl countImpl){

this.countImpl = countImpl;

}

@Override

public void queryCount(){

System.out.println("在调用代理业务类之前执行");

countImpl.queryCount();

System.out.println("在调用代理业务类之后执行");

}

}

d.调用

public static void main(String []args){

CountImpl countImpl = new CountImpl();

CountProxy countProxy = new CountProxy(countImpl);

countProxy.queryCount();

}

缺点:一个代理类只能代理一个业务接口,如果要代理多个业务接口需要定义多个实现类和代理类,如果在调用代理业务类前后的代码是一样的,则多个代理类会有很多冗余代码。

4、动态代理:根据传进来的业务实现类和方法名进行具体调用

JDK动态代理

a.定义业务逻辑接口

public interface BookFacade(){

public void addBook();

}

b.定义业务实现类

public class BookFacadeImpl implements BookFacade(){

@Override

public void addBook(){

System.out.printin("增加图书的方法");

}

}

c.创建动态代理类:InvocationHandler是调用管理接口

public class BookFacadeProxy implements InvocationHandler {

// 业务实现类对象,用来调用具体的业务方法

private Object target;

// 绑定业务对象并返回一个代理类

public Object bind(Object targer) {

this.targer = targer;

// 通过反射机制,创建一个代理类对象并返回实例,用户进行方法调用时使用

// 创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,调用真的的业务方法)、接口、handler实现类

return Proxy.newProxyInstance(this.targer.getClass().getClassLoader(), this.targer.getClass().getInterfaces(), this);

}

// 包装调用方法:进行预处理、调用后处理

public Object invoke(Object proxy, Method method, Object []args) throws Throwable {

Object result = null;

System.out.println("进行预处理");

// 调用真正的业务方法

method.invoke(targer, args)

System.out.println("进行调用后处理");

}

}

d.在使用时,先创建一个业务实现类对象和一个代理类对象,然后定义接口引用(向上转型)并用代理对象.bind(业务实现类对象)的返回值进行赋值,最后通过接口引用调用真实业务方法。(接口引用指向一个绑定了业务类的代理类对象,所以通过接口名调用的是被代理的方法们)

public static void main(String []args) {

BookFacadeImpl bookFacadeImpl = new BookFacadeImpl();

BookFacadeProxy proxy = new BookFacadeProxy();

BookFacade bookFacade = (BookFacade)proxy.bind(bookFacadeImpl);

bookFacade.addBook();

}

缺点:JDK动态代理的代理对象在创建时,需要有业务实现类所实现的接口作为参数(因为后面代理方法需要根据接口内的方法名进行调用)。如果业务实现类没有实现接口而是直接定义接口的话,就无法使用JDK动态代理。并且如果业务实现类中新增了接口中没有的方法,这些方法也是无法被代理的(因为无法调用)。

CGlib动态代理:是根据针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理,(因为采用的是继承,所以不能对final修饰的类进行代理)。

a.定义业务类,无需实现接口

public calss BookFacadeImpl1 {

public void addBook() {

System.out.println("增加一本书");

}

}

b.实现MethodInterceptor方法代理接口,创建代理类

public class BookFacadeCglib implements MethodInterceptor {

// 业务对象类,代理方法中进行真正的业务方法调用

private Object targer;

// 相当于JDK动态代理的bind 绑定

public Object getInstance(Object targer) {

this.targer = targer;

// 创建加强器,用来创建动态代理

Enhancer enhancer = new Enhancer();

// 加强器要指定代理的业务类(即:为下面生成的代理类指定父类)

enhancer.setSupperclass(this.targer.getClass());

// 设置回调:对于代理类上所有方法的调用,都会调用CallBack,

enhancer.setCallBack(this);

// 创建动态代理对象并返回

return enhancer.create();

}

// 实现回调方法

public Object intercept(Object obj, Method method, Object []args, MethodProxy proxy) {

System.out.println("预处理方法");

// 调用父类的方法

proxy.invokeSuper(obj, args);

System.out.println("调用后方法");

}

}

c.创建业务类对象和代理类对象,代理类对象.getInstance(业务类对象)返回一个动态代理对象(它是业务类的子类,可以用业务类引用指向它),最后通过动态代理类对象进行方法调用。

public static void main(String []args) {

BookFacadeImpl1 bookFacadeImpl1 = new BookFacadeImpl1();

BookFacadeCglib bookFacadeCglib = new BookFacadeCglib();

BookFacadeImpl1 bookFacade = (BookFacadeImpl1)bookFacadeCglib.getInstance(bookFacadeImpl1);

bookFacade.addBook();

}

5.静态代理、JDK动态搭理、CGlib动态代理比较:

静态代理:通过在代码中显式定义一个业务类一个代理,在代理类中对业务方法进行包装,用户通过代理类调用被包装过的业务方法。

缺点:每个代理类只能代理一个业务类,如果有多个业务类需要代理则需要些多个代理类

JDK动态代理:通过传进来的业务实现类和方法进行调用业务实现类的同名方法

缺点:如果该业务实现类没有实现接口而是直接定义接口,或者是该业务实现类中增加了接口没有的方法,则就无法被代理类调用

CGlib动态代理:通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行调用

据说原来的CGlib比JDK的动态代理性能要高出很多,但是由于JDK6 7 8逐渐完善,差距越来越小,而且有被反超的可能

猜你喜欢

转载自blog.csdn.net/m0_38016299/article/details/85032773