Java 代理

 

Java的代理在各种框架中大放异彩, 我们也来大致唠唠.

代理的本质一句话总结, 对原函数的包装.

本质都说了, 那就不多xx了, 直接开始. show your code.

代理和java反射分不开, 这里有一篇” java 反射

静态代理

静态代理, 是我们主动进行编码, 没有其余辅助类库注入到我们的代码中.

写一个UserService接口, UserServiceImpl来实现这个接口, 然后我们在UserServiceProxy实现对于UserServiceImpl的代理.

public interface UserService {
    void sayHello();
}
public class UserServiceImpl implements UserService {
    @Override
    public void sayHello() {
        System.out.println("hello");
    }
}
public class UserServiceProxy {
    private UserService userService;

    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }

    public void sayHello() {
        System.out.println("how are you?");
        userService.sayHello();
        System.out.println("goodbye~");
    }
}
    public static void main(String[] args) {
        bootStaticProxy();
    }
    
    private static void bootStaticProxy(){
        UserService service = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy(service);
        proxy.sayHello();
    }

静态代理运行结果

当然, 也可以没有UserService这个接口, 直接代理指定的对象就行.

就是普通的代理模式, 没什么好说的.

JDK动态代理

要使用JDK进行动态代理, 会对代理类的代码有一定的侵入, 因为使用JDK进行动态代理, 要被代理的类必须实现要被代理的接口.

要代理的接口

public interface UserService {
    void sayHello();
}

要被代理的类

public class UserServiceImpl implements UserService {
    @Override
    public void sayHello() {
        System.out.println("hello");
    }
}

实现代理的类

public class UserServiceProxyByJdk implements InvocationHandler {
    private Object target;

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

    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("---begin " + method.getName());
        Object result = method.invoke(target, objects);
        System.out.println("---end " + method.getName());
        return result;
    }
	
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                , target.getClass().getInterfaces(), this);
    }
}

getProxy()方法可以写在生成代理对象逻辑中, 这是一个适配器, 方便调用.

    private static void bootJdkProxy(){
        UserService service = new UserServiceImpl();
        UserServiceProxyByJdk userServiceProxyByJdk = new UserServiceProxyByJdk(service);
        UserService userServiceProxy = (UserService) userServiceProxyByJdk.getProxy();
        userServiceProxy.sayHello();
    }

使用JDK进行代理结果截图

使用cglib进行动态代理

cglib 项目地址:https://github.com/cglib/cglib

cglib是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,cglib是一个好的选择。

cglib 原理: 动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。

cglib 底层: 使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

cglib 无法对final方法进行代理

代理的方法的接口 (cglib不需要接口, 这个只是为了与上面统一, 可有可无)

public interface UserService {
    void sayHello();
}

要被代理的类

public class UserServiceImpl implements UserService {
    public void sayHello() {
        System.out.println("hello");
    }
}

实现代理

public class CglibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("how are you?");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("goodbye");
        return result;
    }
}

要实现cglib代理, 需要有类实现MethodInterceptor接口中的Intercept方法, 然后传入enhancer, 由enhancer负责代理对象的生成.

cglib代理对象的生成调用结果