动态代理
- 作用:在不改变源码的基础上,对原有的方法进行增强实现,也是后面Spring AOP面向切面编程思想的实现技术
- 分类:JDK提供的动态代理(基于接口的动态代理)、cglib提供的动态代理(基于子类的动态代理)
- 实例代码:使用两种代理方式分别对下面的UserServiceImpl类进行增强
UserService接口类
package com.bran.service;
public interface UserService {
void save();//保存操作
void delete();//删除操作
void update();//更新操作
void find();//查找操作
}
UserServiceImpl类
package com.bran.service;
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存操作");
}
@Override
public void delete() {
System.out.println("删除操作");
}
@Override
public void update() {
System.out.println("更新操作");
}
@Override
public void find() {
System.out.println("查找操作");
}
}
JDK提供的动态代理
- 特点:基于接口的动态代理,并且只能对实现接口里面的方法进行增强
- 要求:被代理类必须实现至少一个接口
- 提供者:JDK自带
- 步骤:创建UserServiceProxyFactory类,用来生成动态代理对象
package com.bran.proxytest; import com.bran.service.UserService; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // JDK动态代理 public class UserServiceProxyFactory implements InvocationHandler { private UserService userService; //传入被代理对象 public UserServiceProxyFactory(UserService userService) { super(); this.userService = userService; } /** * 获取UserService的代理对象 * 创建代理对象的方式为Proxy.newProxyInstance(ClassLoader loader, * Class<?>[] interfaces, * InvocationHandler h) * 需要传入3个参数值 * ClassLoader loader:被代理对象的类加载器,一般是固定写法 * Class<?>[] interfaces:被代理类实现的所有接口,要求被代理类最少实现一个接口,固定写法 * InvocationHandler h :一个接口,要传入该接口的实现类对象,里面invoke方法里要写着对代理对象的方法的具体增强 * @return */ public UserService getUserServiceProxy() { //创建代理对象 UserService userServiceProxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), this); return userServiceProxy; } /** * 执行被代理对象的任何接口方法时都会经过该方法(只能对接口方法增强) * @param proxy 代理对象的引用(给JDK使用的,一般我们用不到) * @param method 当前执行的方法 * @param args 当前执行方法所需要的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //对方法进行增强实现 System.out.println("=========================="); System.out.println("打开事务"); Object returnValue = method.invoke(userService, args);//利用反射执行方法 System.out.println("提交事务"); System.out.println("=========================="); //也可以对UserServiceImpl类的特定方法进行增强 // if("delete".equals(method.getName())) { // System.out.println("222222222222222"); // } // Object invoke = method.invoke(userService, args); return returnValue; } }
测试类
package com.bran.proxytest; import com.bran.service.UserService; import com.bran.service.UserServiceImpl; import org.junit.Test; //测试JDK动态代理 public class Demo { @Test public void testProxy() { //创建被代理对象 UserService service = new UserServiceImpl(); UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(service); //生成代理对象 UserService proxyUserService = proxyFactory.getUserServiceProxy(); //执行方法 proxyUserService.delete(); proxyUserService.find(); //判断代理对象和被代理类的关系 System.out.println(proxyUserService instanceof UserService); System.out.println(proxyUserService instanceof UserServiceImpl); } }
输出结果
-
结果分析:由结果看出,代理对象的方法都是已经对被代理类的方法进行加强过的,模拟添加了打开事务和提交事务的操作;代理类和被代理类只是实现同一个接口,且代理对象不是被代理类的实例。所以被代理类里的不是实现接口的方法是不能进行代理的。
cglib提供的动态代理
- 特点;基于子类的动态代理,通过继承被代理类来重写方法从而对方法的增强,被final修饰的方法不能增强,不需要被代理类实现接口
- 要求:被代理类不能是最终类,不能被final修饰,必须是可继承的
- 提供者:cglib
- 使用要求:必须导入cglib的包才能使用cglib动态代理
<!-- 使用Maven导入cglib的包--> <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency>
-
步骤:创建UserServiceProxyFactory类,用来生成动态代理对象
package com.bran.proxytest; import com.bran.service.UserService; import com.bran.service.UserServiceImpl; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; //cglib代理 public class UserServiceProxyFactory implements MethodInterceptor { private UserServiceImpl userServiceImpl; //传入要代理的对象 public UserServiceProxyFactory(UserServiceImpl userServiceImpl) { super(); this.userServiceImpl = userServiceImpl; } /** * 获取UserService的代理对象 * 创建代理对象的方式为Enhancer.create(Class type, Callback callback); * 参数: * Class type :指定被代理对象的字节码 * Callback callback:一个接口,一般都是传入该接口的子接口MethodInterceptor的实现类对象,里面写对方法增强的具体实现 * * @return */ public UserServiceImpl getUserServiceImpl() { UserServiceImpl proxyUserServiceImpl = (UserServiceImpl) Enhancer.create(userServiceImpl.getClass(), this);//创建代理对象 /* //也可以这种方式创建代理对象,两种方式是一样的 Enhancer en = new Enhancer();//创建代理对象生成器,可以动态生成代理对象 en.setSuperclass(userService.getClass());//设置对谁进行代理 en.setCallback(this);//代理要做什么 UserService proxyUserService = (UserService) en.create();//创建代理对象 */ return proxyUserServiceImpl; } /** * 执行被代理对象的方法时都会执行该方法 * @param proxyobj 代理对象的引用 * @param method 当前执行的方法 * @param args 当前执行方法所需要的参数 * @param methodProxy 当前执行方法的代理对象,是cglib生成对method的一个代理,可以用也可以不用 * @return * @throws Throwable */ @Override public Object intercept(Object proxyobj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //对方法进行增强实现 System.out.println("=========================="); System.out.println("打开事务"); Object returnValue = methodProxy.invokeSuper(proxyobj, args);//执行被代理对象的方法,要传入的是代理对象 /** * 也可以这么写 * Object returnValue = methodProxy.invoke(userService, args);//执行当前方法,要传入被代理对象 * Object returnValue = method.invoke(userService, args); */ System.out.println("提交事务"); System.out.println("=========================="); return returnValue; } }
测试类
package com.bran.proxytest; import com.bran.service.UserService; import com.bran.service.UserServiceImpl; import org.junit.Test; public class Demo { @Test public void testProxy() { //创建被代理对象 UserServiceImpl userService = new UserServiceImpl(); UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(userService); //生成代理对象 UserServiceImpl proxyUserService = proxyFactory.getUserServiceImpl(); proxyUserService.update(); proxyUserService.save(); System.out.println(proxyUserService instanceof UserServiceImpl); } }
运行结果
-
结果分析:从输出可以看出,代理对象对原有的方法进行了增强,模拟添加了打开事务和提交事务的操作,并且也能得出代理对象是被代理类的一个实例,也能看出代理类似继承与被代理类。