JDK动态代理
-
知识点:
- JDK动态代理是基于接口的代理,通过反射机制动态生成代理类。
- 代理类实现了被代理接口,并在代理类中调用InvocationHandler接口的invoke方法来实现对被代理方法的增强。
-
注意点:
- 被代理类必须实现接口,否则无法使用JDK动态代理。
- JDK动态代理只能代理实现了接口的类,无法代理没有实现接口的类。
-
常见场景:
- AOP(面向切面编程):在方法执行前后进行一些额外操作,比如日志记录、性能监控等。
- 事务管理:在方法执行前后开启、提交或回滚事务。
CGLIB代理
-
知识点:
- CGLIB代理是基于继承的代理,通过继承被代理类来实现代理。
- CGLIB代理不要求被代理类实现接口,可以代理没有实现接口的类。
-
注意点:
- CGLIB代理生成的代理类是被代理类的子类。
- 由于CGLIB代理是基于继承的,因此无法代理final类和final方法。
-
常见场景:
- 对没有实现接口的类进行代理。
- 对类的方法进行增强,而不需要修改原始类的代码。也可以做AOP
-
问题:
-
请解释JDK动态代理的原理。
-
JDK动态代理和静态代理有什么区别?举例说明。
-
请解释CGLIB代理的原理。
CGLIB(Code Generation Library)是一个功能强大的代码生成库,用于在运行时生成字节码并创建代理对象。CGLIB代理是一种基于继承的动态代理方式,与基于接口的动态代理(如JDK动态代理)不同。CGLIB代理的原理是通过继承目标类并重写其方法来创建代理对象。当使用CGLIB代理时,CGLIB会在运行时动态生成一个新的类,该类继承自目标类,并在其中重写需要代理的方法,并在重写的方法中调用被代理类的super方法。这样可以保证代理类在执行代理方法时能够调用到被代理类的原始实现。
例如,如果被代理类有一个方法叫做
doSomething()
,那么CGLIB代理会生成一个子类,并在子类中重写doSomething()
方法。在重写的方法中,会先调用被代理类的super.doSomething()
,然后再执行代理逻辑。这样就能够保证代理类在执行代理方法时能够调用到被代理类的原始实现。然后,通过调用这个新生成的类的实例来实现代理功能。相比于基于接口的动态代理,CGLIB代理可以代理没有实现接口的类,也可以代理类的final方法。但是,由于CGLIB是通过生成子类来实现代理的,所以无法代理final类。
-
CGLIB代理和JDK动态代理有什么区别?举例说明。
JDK动态代理是通过Java反射机制实现的,它要求被代理的类必须实现一个或多个接口。在运行时,JDK动态代理会动态生成一个实现了代理接口的代理类,并在代理类的方法中调用InvocationHandler接口的invoke方法来实现代理逻辑。
CGLIB代理是通过继承目标类来实现的,它不要求目标类实现接口。在运行时,CGLIB会动态生成一个目标类的子类,并重写目标类的方法来实现代理逻辑。
jdk代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ServiceProxyHandler implements InvocationHandler {
private Object target;
public ServiceProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
if (method.getName().equals("save")||method.getName().equals("update")){
try {
System.out.println(method.getName()+"事务执行前");
result= method.invoke(target, args);
System.out.println(method.getName()+"事务执行后");
} catch (Exception e) {
throw new RuntimeException("操作执行失败,事务回滚");
} finally {
System.out.println("后置通知");
}
return result;
}else {
return method.invoke(target, args);
}
}
}
/**
* JDK代理是对接口的代理,适用于只实现了接口的类
*/
public class TestJDKProxy {
public static void main(String[] args) {
BookService bookService = new BookServiceImpl();
ServiceProxyHandler userServiceProxyHandler = new ServiceProxyHandler(bookService);
BookService o = (BookService) Proxy.newProxyInstance(bookService.getClass().getClassLoader(),
bookService.getClass().getInterfaces(), userServiceProxyHandler);
o.save();
System.out.println();
o.select();
System.out.println();
o.update();
}
}
Cgclib代理
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyInterceptor implements MethodInterceptor {
/**
* 1. Object o: 这个参数表示被代理的对象。
* 2. Method method: 这个参数表示正在被调用的方法。
* 3. Object[] objects: 这个参数是一个包含被调用方法的参数的数组。
* 4. MethodProxy methodProxy: 这个参数是用于调用原始方法的代理对象。
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {
Object result = null;
if (method.getName().equals("save")||method.getName().equals("update")||method.getName().equals("delete")){
try {
System.out.println("前置通知");
result = methodProxy.invokeSuper(o, objects);
System.out.println("事务处理完成");
} catch (Throwable throwable) {
System.out.println("事务异常,回滚事务!");
throwable.printStackTrace();
} finally {
System.out.println("后置通知");
}
}else{
try {
result = methodProxy.invokeSuper(o, objects);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
return result;
}
}
import edu.lzlg.proxy.service.impl.BookServiceImpl;
import net.sf.cglib.proxy.Enhancer;
/**
* CGCLIB代理是对类的代理,所以可以适用于类独有的方法
*/
public class TestCGCLIB {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(BookServiceImpl.class);
enhancer.setCallback(new MyInterceptor());
BookServiceImpl bookService = (BookServiceImpl) enhancer.create();
bookService.save();
System.out.println();
bookService.update();
System.out.println();
bookService.select();
System.out.println();
bookService.delete();
}
}