jdk实现动态代理步骤
1.创建一个接口和实现接口的类(这个就是我们要增强或者补充的方法)
package com.demo.jdk;
public interface UserService {
public void run();
}
package com.demo.jdk;
public class UserServiceImp implements UserService{
@Override
public void run() {
System.out.println("run");
}
public static void main(String[] args) {
UserService proxy = new MyInvocationHandlerDemo(new UserServiceImp()).getProxy();
proxy.run();
}
}
2.创建一个实现接口InvocationHandler的类,并实现invoke方法(在invoke方法里面 对原方法进行增强或者补充)
package com.demo.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandlerDemo implements InvocationHandler {
private Object target;
public MyInvocationHandlerDemo(Object target) {
this.target = target;
}
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(UserService.class.getClassLoader(),new Class[]{UserService.class},this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
method.invoke(target,args);
System.out.println("end");
return null;
}
}
3.测试类中 ,通过Proxy的静态方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理 返回接口,调用具体方法
上面那个main方法就可以运行
JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。
cglib实现动态代理步骤
0.引入jar
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
1.创建一个类 (要增加类里的方法)
package com.demo.cglib;
public class SayHello {
public void say() {
System.out.println("hello everyone");
}
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SayHello proxyImp = (SayHello) proxy.getProxy(SayHello.class);
proxyImp.say();
}
}
2.自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似(通过 Enhancer 类的 create()创建代理类)
package com.demo.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("后置代理");
return result;
}
}
3.测试代码
JDK 动态代理和 CGLIB 动态代理对比
JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。
就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。