两者有何区别
1、Jdk动态代理:利用拦截器(必须实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
JDK动态代理主要是通过,反射包中的Porxy类和InvokationHandler接口。它们结合在一起后可以创建动态代理类。Porxy类基于传递的参数创建动态代理类。InvokationHandler则用于激发动态代理类的方法。这个过程是在程序执行过程中动态生成与处理的,所以叫动态代理。
2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理
所以:
- 如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用;
- 如果想要使用CGlib动态代理,那么代理类不能使用final修饰类和方法;
还有: 在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理。
JDk动态代理例子
UserService接口
1
2
3
4
5
6
7 public interface UserService {
void addUser();
void updateUser(String str);
}UserServiceImpl实现类
1
2
3
4
5
6
7
8
9
10
11 public class UserServiceImpl implements UserService {
public void addUser() {
System.out.println("添加用户");
}
public void updateUser(String str) {
System.out.println("更新用户信息" + str);
}
}UserProxy代理类,实现InvocationHandler接口重写invoke方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 public class UserProxy implements InvocationHandler {
private Object target;
public UserProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(target, args);
System.out.println("记录日志");
return res;
}
}test测试类
1
2
3
4
5
6
7
8
9
10
11 public class test {
public static void main(String[] args) {
UserServiceImpl impl = new UserServiceImpl();
UserProxy userProxy = new UserProxy(impl);
UserService userService = (UserService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),userProxy);
userService.addUser();
userService.updateUser(":我是滚韬");
}
}
CGLIB动态代理
首先要加入依赖
1
2
3
4
5 <dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>具体类
1
2
3
4
5
6
7
8 public class Hello {
public String sayHello(boolean throwException) throws Exception {
System.out.println("hello everyone!");
if(throwException)
throw new Exception("test exception");
return "123";
}
}实现MethodInterceptor接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class ProxyFactory implements MethodInterceptor {
//要代理的原始对象
private Object obj;
public Object createProxy(Object target) {
this.obj = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.obj.getClass());// 设置代理目标
enhancer.setCallback(this);// 设置回调
enhancer.setClassLoader(target.getClass().getClassLoader());
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = null;
try {
// 前置通知
before();
result = proxy.invokeSuper(obj, args);
// 后置通知
after();
} catch (Exception e) {
exception();
}finally{
beforeReturning();
}
return result;
}
private void before() {
System.out.println("before method invoke");
}
private void after() {
System.out.println("after method invoke");
}
private void exception() {
System.out.println("method invoke exception");
}
private void beforeReturning() {
System.out.println("before returning");
}
}测试类
1
2
3
4
5
6
7
8
9
10 public class EnhancerTest {
public static void main(String[] args) throws Exception {
Hello hello = new Hello();
ProxyFactory cglibProxy = new ProxyFactory();
Hello proxy = (Hello) cglibProxy.createProxy(hello);
String result=proxy.sayHello(true);
System.out.println(result);
}
}
两个动态代理的使用场景是哪里
我们主要是在Spring Aop项目中去使用它们
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 >
>public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
//如果
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
>}
>1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理
>2、如果目标对象实现了接口,也可以强制使用CGLIB
>3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换如果需要强制使用CGLIB来实现AOP,需要配置spring.aop.proxy-target-class=true或**@EnableAspectJAutoProxy(proxyTargetClass = true**
(补充)Porxy类
Porxy类提供了一个静态方法创建动态代理类。
1 | public static Object newProxyInstance(ClassLoader loader, |
1、ClassLoader:
ClassLoader会定义动态代理类,ClassLoader可以通过类或者接口获得,如果我们想通过接口获得,调用方法如下。
1 | Task.class.getClassLoader() |
如果通过类来获得,加入我们有一个类TaskImpl实现了Task接口,我们有个TaskImpl的对象ob,然后ClassLoader获取方法如下
1 | ob.getClassLoader() |
2、 Class<?>[] interfaces:动态代理类需要实现的接口
3、InvocationHandler:传递一个实现了InvokationHandler接口的类的实例
InvokationHandler是Java 反射包里面的一个接口。InvokationHandler通过用户类来实现,来激发一个动态代理类的方法。它只有一个方法:
1 >public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;1、Object:实现方法的代理对象
2、Method:代理实例激发的方法,Porxy参数中的接口方法
3、Object[]:传递给方法的一系列参数