JDK代理
代理条件:实现统一接口
目标类
public class UserServiceImpl implements UserService {
/**
* 目标方法
* @param user
* @return
*/
public int addUser(User user) {
System.out.println("正在新增User对象到数据库..."+user);
return 1;
}
/**
* 目标方法
* @param user
* @return
*/
public int updateUser(User user) {
System.out.println("正在更新User对象到数据库..."+user);
return 1;
}
/**
* 目标方法
* @param user
* @return
*/
public int deleteUser(User user) {
System.out.println("正在删除User对象到数据库..."+user);
return 1;
}
}
动态代理通过拦截器为目标类生成代理类
public class ObjectInterceptor implements InvocationHandler {
Transaction tx=new Transaction();
Object target=null; //目标对象
public ObjectInterceptor(Object target){
this.target=target;
}
/**
* 执行拦截的方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
tx.openTx();
//调用目标对象的目标方法
Object result=method.invoke(target,args);
tx.closeTx();
return result;
}
}
反射中类method,指代目标方法
method.invoke调用反射中(带有指定参数的指定对象调用此method对象表示的底层方法)
此代理中Object result=method.invoke(target,args);
等同于Object result=method.invoke(userService,args);目标对象中的方法
为通用性,创建通用目标对象,再使用构造方法传入
Object target=null; //目标对象
public ObjectInterceptor(Object target){
this.target=target;
}
测试类
public class TestProxy {
@Test
public void test1(){
//拦截器对象
ObjectInterceptor h=new ObjectInterceptor(new UserServiceImpl());
// us 本质是代理类对象
// JDK动态代理:使用JDK动态代理自动生成一个代理类对象 com.sun.proxy.$Proxy4,因为$Proxy4在底层JDK生成的!!!
UserService us= (UserService)
Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),UserServiceImpl.class.getInterfaces(),h);
// addUser 是代理类对象的方法
int count1 = us.addUser(new User(8989, "老王", "人妻"));
System.out.println(count1>0?"新增成功":"新增失败");
System.out.println("----------------------------------------------------------");
int count2 = us.addUser(new User(8080, "小王", "人妻"));
System.out.println(count1>0?"更新成功":"更新失败");
printClass();
}
public static void printClass(){
try {
//把JDK动态代理生成的代理类的class文件输出到硬盘上,方便观察
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy4", UserServiceImpl.class.getInterfaces());
String path="D:/jdkproxy/" + "$Proxy4.class";
System.out.println(path);
//字节输出流
FileOutputStream out = new FileOutputStream(path);
out.write(classFile);
out.close();
System.out.println("自动生成的代理类class文件输出成功~");
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
验证代理的真实存在,使用printClass()将代理类打印到硬盘进行观察
Proxy.newProxyInstance(UserServiceImpl.class.getClassLoader(),UserServiceImpl.class.getInterfaces(),h);
通过反射中的Proxy类调用方法newProxyInstance创建一个代理类
传入参数 类加载器(UserServiceImpl.class.getClassLoader()),实现接口(UserServiceImpl.class.getInterfaces())
当代理类用UserServiceImpl接收时,报错:类转换异常
体现了多态
CGLIB代理
一个强大的,高性能的代码生成库,被广泛运用于AOP框架
代理主要是通过对字节码的操作,为对象引入间接级别,以控制对象的访问
底层使用ASM(一个短小精悍的字节码操作框架)来操作字节码新生成的类(子类),重写父类中过的方法。
导入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
拦截器
public class ObjectInterceptor implements MethodInterceptor {
Transaction tx=new Transaction();
/**
* 执行拦截的方法
* @param o
* @param method
* @param agrs
* @param methodProxy
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] agrs, MethodProxy methodProxy) throws Throwable {
tx.openTx();
//调用目标对象的目标方法,父类
Object result=methodProxy.invokeSuper(o,agrs);
tx.closeTx();
return result;
}
}
测试类,打印验证代理类
public class TestProxy {
@Test
public void test1() throws Exception {
// 在指定目录下生成CGLIB动态代理类子类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\classcglib123");
//创建拦截器对象
ObjectInterceptor interceptor = new ObjectInterceptor();
//作用通过字节码生成真实类的子类对象
Enhancer enhancer = new Enhancer();
//谁是父类UserServiceImpl.class--->子类()
enhancer.setSuperclass(UserServiceImpl.class);
//设置子类中方法的拦截器
enhancer.setCallback(interceptor);
//生成代理类子类对象 us是UserServiceImpl类的对象嘛?
UserServiceImpl us = (UserServiceImpl) enhancer.create();
String name = us.getClass().getName();
System.out.println(name);
// addUser 是代理类对象的方法
int count1 = us.addUser(new User(8989, "老王", "人妻"));
System.out.println(count1 > 0 ? "新增成功" : "新增失败");
System.out.println("----------------------------------------------------------");
int count2 = us.updateUser(new User(8080, "小王", "人妻"));
System.out.println(count1 > 0 ? "更新成功" : "更新失败");
System.out.println("=========CGLIB$CALLBACK_0==========");
//
Field h = us.getClass().getDeclaredField("CGLIB$CALLBACK_0");
//暴力反射 CGLIB$CALLBACK_0为私有属性
h.setAccessible(true);
Object obj = h.get(us);
//class com.bruceliu.service.impl.interceptor.ObjectInterceptor 证明CGLIB$CALLBACK_0属性为拦截器
System.out.println(obj.getClass());
}
}
逻辑
自动代理生成子类,子类方法调用,子类方法中调用拦截器方法(拦截器中添加事务给功能),拦截器中调用父类方法。
效果
拦截器方法执行时打印事务,调用父类方法输出,再执行事务关闭,最后执行测试类中的输出。