在spring AOP中,由于通知类中抽取了原始对象中的公共方法,使得原始对象的方法变得不能进行完整的操作。但是我们还是想通过某个方式实现原始对象完成完整操作,我们可以通过为原始对象创建代理对象的方式达到目的,有两种方式:JDK动态代理和cglib动态代理。
一、JDK动态代理
1、概述:针对内存中的Class对象,使用类加载器,动态为目标对象的实现接口创建代理对象。也就是说JDK代理是对对象做代理。
2、具体实现(如下代码):
创建一个接口及实现类
public interface UserDao {
public void add();
}
public class UserDaoImp implements UserDao {
@Override
public void add() {
System.out.println("新增用户操作");
}
}
创建实现JDK动态代理的工具类
public class JdkProxy implements InvocationHandler {
private UserDao userDao;
// 定义一个方法用于创建JDK代理对象
public UserDao createProxyObject(UserDao userDao) {
// 被代理对象作为参数传入进来
this.userDao = userDao;
// 获取类加载器:对谁代理,使用谁的类加载器
ClassLoader classLoader = userDao.getClass().getClassLoader();
// 获取被代理对象的所有实现接口
Class<?>[] interfaces = userDao.getClass().getInterfaces();
// 创建Handler对象,用于增强拦截,为了方便调用使用实现InvocationHandler接口的方式
InvocationHandler h = this;
Object obj = Proxy.newProxyInstance(classLoader, interfaces, h);
return (UserDao) obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("连接数据库");// 增强操作
// 对原始操作进行调用(使用反射)
method.invoke(userDao, args);
System.out.println("关闭数据库");
return null;
}
public static void main(String[] args) {
// 1、创建一个对象
UserDao dao = new UserDaoImp();
// 2、为原始对象创建代理对象
UserDao daoProxy = new JdkProxy().createProxyObject(dao);
// 3、使用代理对象运行操作
daoProxy.add();
}
}
二、cglib动态代理
1、概述:非接口实现的对象,对于不使用接口的业务类,无法使用JDK动态代理。cglib采用底层字节码急速,可以为一个类创建子类,也就是cglib是解决无接口代理问题,
是对类做代理。
2、具体实现(如下代码)
创建Person类及生成代理的方法
public class Person {
public void action() {
System.out.println("Java程序员");
}
}
public Person createProxyObject(Class clazz) {
// cglib中的核心对象是Enhance,用来在内存中创建一段动态的类的字节码
Enhancer enhancer = new Enhancer();//此时没有做继承
// 为其指定父类,除了完成继承关系外,还将父类所有的方法反射过来,并在自己的类中创建这些方法
enhancer.setSuperclass(clazz);
// 进行功能的增强
// 设置方法的调用拦截
Callback callback = new MethodInterceptor() {
// proxy:代理对象
// method:被拦截的方法对象
// args:调用函数
// methodProxy:使用代理机制创建被代理对象的方法
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// 做增强
System.out.println("Java后端程序员还会烤肉");
// 调用原始的操作
Object ret = methodProxy.invokeSuper(proxy, args);
return ret;
}
};
// 设置具体的回调操作
enhancer.setCallback(callback);
// 创建内存中全新类的对象
Object proxyObj = enhancer.create();
return (Person) proxyObj;
}
3、小结:cglib动态代理机制其实是利用继承的思想来实现,在代码中可以看出,代理机制创建代理对象,把被代理的对象当做父类,把代理的对象
当做子类,走父类运行,走子类的实现,这体现了继承与多态的思想。
三、总结
cglib可以对任意的类进行代理,JDKdial只能对接口实现的类进行代理。