动态代理两种实现方式(jdk动态代理和CGLib动态代理)

前言

关于动态代理和静态代理,我这篇博文https://blog.csdn.net/Jet_Green/article/details/81198691中写的很详细,这里主要写jdk的动态代理和CGLib动态代理的区别和优化

JDK动态代理

首先定义个hello接口:


public interface Hello {
    void say(String name);
}

然后写一个实现类:

public class HelloImpl implements Hello{

    @Override
    public void say(String name) {
        System.out.println("Hello" + name);
    }

}

接下来实现InvocationHandler接口并重写invoke方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy implements InvocationHandler{
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }

    private void before() {
        System.out.println("before");
    }

    private void after() {
        System.out.println("After");
    }
}

写一个主类运行:


import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {
        Hello hello = new HelloImpl();

        DynamicProxy dynamicProxy = new DynamicProxy(hello);

        Hello helloProxy = (Hello)Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),
                hello.getClass().getInterfaces(),
                dynamicProxy
                );              
        helloProxy.say("Jack");
    }
}

但是这样的写法有些麻烦我们可以重写getProxy方法

@SuppressWarnings("unchecked")
    public  T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

在主类方法中就可以这么调用。

package 动态代理的两种方式;

import java.lang.reflect.Proxy;

public class Main {

    public static void main(String[] args) {

        Hello hello = new HelloImpl();

        DynamicProxy dynamicProxy = new DynamicProxy(hello);

        Hello helloProxy = dynamicProxy.getProxy();

        helloProxy.say("Jack");
    }
}

这样所有的代理类就都合并到动态代理类中了,但这样做仍然存在一个问题:JDK给我们提供的动态代理接口只能代理接口,而不能代理没有接口的类。那么解决这个问题的办法就是用CGLib动态代理

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLibProxy implements MethodInterceptor {

    public  T getProxy(Class cls){
        return (T) Enhancer.create(cls,this);
    }
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj,args);
        after();
        return result;
    }

    private void before() {
        System.out.println("before");
    }

    private void after() {
        System.out.println("After");
    }
}

Main方法调用使用:

public static void main(){
    CGLibProxy cgLibProxy = new CGLibProxy();

    Hello helloProxy = cgLibProxy.getProxy(HelloImpl.class);

    helloProxy.say("Jack");

}

这里可以做个优化,不用每次用的时候都要new一次,可以用单例模式来改良。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLibProxy implements MethodInterceptor {

    private static CGLibProxy instance = new CGLibProxy();

    private CGLibProxy(){

    }

    public static CGLibProxy getInstance(){
        return instance;
    }

    public  T getProxy(Class cls){
        return (T) Enhancer.create(cls,this);
    }
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object result = proxy.invokeSuper(obj,args);
        after();
        return result;
    }

    private void before() {
        System.out.println("before");
    }

    private void after() {
        System.out.println("After");
    }
}

这样Main方法就可以这样这样写了:

public class Main {
    public static void main(String[] args){
        //CGLibProxy cgLibProxy = new CGLibProxy();

        Hello helloProxy = CGLibProxy.getInstance().getProxy(HelloImpl.class);
        helloProxy.say("Jack");

    }
}

当然CGLib动态代理也有缺点,它是通过继承来实现动态代理的,所以它不能动态代理有final修饰的类。

参考文献《架构探险 从零开始写javaweb》

你可能感兴趣的:(Java)