jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让目标类和代理类实现同一接口,代理类持有目标类对象,来达到方法拦截的作用,这样通过接口的方式有两个弊端,一个是必须保证target类有接口,第二个是如果想要对target类的方法进行代理拦截,那么就要保证这些方法都要在接口中声明,实现上略微有点限制。
jdk动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用业务方法前调用InvocationHandler处理。 代 理 类 必 须 实 现 I n v o c a t i o n H a n d l e r 接 口 , 并 且 , J D K 动 态 代 理 只 能 代 理 实 现 了 接 口 的 类 , 没 有 实 现 接 口 的 类 是 不 能 实 现 J D K 动 态 代 理 。 \color{red}{代理类必须实现InvocationHandler接口,并且,JDK动态代理只能代理实现了接口的类,没有实现接口的类是不能实现JDK动态代理。} 代理类必须实现InvocationHandler接口,并且,JDK动态代理只能代理实现了接口的类,没有实现接口的类是不能实现JDK动态代理。 结合下面案例代码来看就比较清晰了。
接口:
public interface Dongwu {
void pao();
void zou();
}
public class Dog implements Dongwu{
@Override
public void pao() {
System.out.println("pao====");
}
@Override
public void zou() {
System.out.println("zou====");
}
}
代理增强类:
public class ProxyHandler implements InvocationHandler {
private Object object;
public ProxyHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception
{
before();
Object invoke = method.invoke(object, args);
after();
return invoke;
}
// 生成代理类
public Object CreatProxyedObj()
{
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), new ProxyHandler(object));
}
public void after(){
System.out.println("之后处理。。。。。。。。");
}
public void before(){
System.out.println("之前处理。。。。。。。。");
}
}
public class Test {
public static void main(String[] args) {
Dongwu dog = new Dog();
Dongwu o = (Dongwu)new ProxyHandler(dog).CreatProxyedObj();// 强制转换类型必须是接口
o.pao();
}
}
1、编写需要被代理的类和接口(我这里就是OrderServiceImpl、OrderService);
2、编写代理类(例如我这里的DynamicLogProxy),需要实现InvocationHandler接口,重写invoke方法;
3、使用Proxy.newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务方法。
基于操作字节码,通过加载代理对象的类字节码,为代理对象创建一个子类,并在子类中拦截父类方法并织入方法增强逻辑。底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的。
在上面几个类的基础上新加了一个没有实现接口的类
新加类:
public class Person {
public void eat(){
System.out.println("吃饭");
}
public void pao(){
System.out.println("pao");
}
}
cjlib代理类:
public class ProxyHandler implements MethodInterceptor {
private Object object;
public void before(){
System.out.println("之前处理。。。。。。。。");
}
public void after(){
System.out.println("之后处理。。。。。。。。");
}
public ProxyHandler(Object object){
this.object = object;
}
public Object CreatProxyedObj() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.object.getClass());
// 设置回调方法
enhancer.setCallback(this);
// 返回代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}
}
public class Test {
public static void main(String[] args) {
Person per = new Person();
Person o= (Person)new ProxyHandler(per).CreatProxyedObj();
o.pao();
}
}
1.使用JDK动态代理,目标类必须实现的某个接口,如果 某 个 类 没 有 实 现 接 口 \color{red}{某个类没有实现接口} 某个类没有实现接口则不能生成代理对象。
2.CGLIB通过继承的方式进行代理、无论目标对象没有没实现接口都可以代理,但是 无 法 处 理 f i n a l \color{red}{无法处理final} 无法处理final的情况(final修饰的方法不能被覆写)
3.性能方面:JDK > CGLIB