前言
面试题:讲讲jdk动态代理,cglib区别,实现原理,优缺点,怎么实现方法的调用的
代理模式
代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能
一个比方:在租房的时候,有的人会通过房东直租,有的人会通过中介租房。
这两种情况哪种比较方便呢?当然是通过中介更加方便。
这里的中介就相当于代理,用户通过中介完成租房的一系列操作(看房、交押金、租房、清扫卫生)代理模式可以有效的将具体的实现与调用方进行解耦,通过面向接口进行编码完全将具体的实现隐藏在内部。
静态代理: 在编译时就已经实现,编译完成后代理类是一个实际的class文件
动态代理: 在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
静态代理
使用方式
创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。
public interface UserDao {
void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("正在保存用户...");
}
}
public class TransactionHandler implements UserDao {
//目标代理对象
private UserDao target;
//构造代理对象时传入目标对象
public TransactionHandler(UserDao target) {
this.target = target;
}
@Override
public void save() {
//调用目标方法前的处理
System.out.println("开启事务控制...");
//调用目标对象的方法
target.save();
//调用目标方法后的处理
System.out.println("关闭事务控制...");
}
}
public class Main {
public static void main(String[] args) {
//新建目标对象
UserDaoImpl target = new UserDaoImpl();
//创建代理对象, 并使用接口对其进行引用
UserDao userDao = new TransactionHandler(target);
//针对接口进行调用
userDao.save();
}
}
使用JDK静态代理很容易就完成了对一个类的代理操作。但是JDK
静态代理的缺点也暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐
JDK动态代理
使用JDK动态代理的五大步骤:
-
通过实现InvocationHandler接口来自定义自己的InvocationHandler;
-
通过
Proxy.getProxyClass
获得动态代理类; -
通过反射机制获得代理类的构造方法,方法签名为
getConstructor(InvocationHandler.class)
; -
通过构造函数获得代理对象并将自定义的
InvocationHandler
实例对象传为参数传入; -
通过代理对象调用目标方法;
public interface IHello {
void sayHello();
}
public class HelloImpl implements IHello {
@Override
public void sayHello() {
System.out.println("Hello world!");