首页 > 代码库 > Java动态代理浅度分析

Java动态代理浅度分析

前言:

我在工作中遇到一种情况:有些程序员在面试的时候对知识点掌握的很优秀,而写代码却很吃力,他们往往侧重于知识本身,对应用略有不足,就像空有一把利剑,却不会使用一样,于是乎就想写一些不一样的文章,内容可能很白,重点是在整个讲解过程中的切入角度以及思考方式。

本文和别的文章有所不同,不从底层次来分析动态代理,仅仅为了程序员在工作中使用。

正文:

先写一个简单的案例,引出来动态代理。

假使我们项目中有对用户删除的业务处理,放在业务层中(尽量做到面向接口编程,测试类很有必要贴出来)

原始代码:定义接口、业务类、测试类

/**
 * 用户业务接口
 */
public interface UserService{
    // 删除用户
    public void delUser(String id);
}

/**
 * 用户业务实现类
 */
public class UserServiceImpl implements UserService {
    
    @Override
    public void delUser(String id) {
        System.out.println("这是删除用户" + id + "的操作...");
    }
}

/**
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        UserService service = new UserServiceImpl();
        service.delUser("10002");
    }
}

如果在像增、删、改这些操作前/后做一些别的工作,比如记录日志,同步数据到别的系统等。

我们往往不会把这些非代码写到业务类中,有很多方式可以实现,这里采用代理的方式(先从最简单的静态代理开始):

完善代码1:添加代理类,修改测试类

 

/**
 * 用户业务代理类
 */
public class UserServiceProxy implements UserService {

    public UserService userService;
    
    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }
    
    @Override
    public void delUser(String id) {
        System.out.println("记录日志");
        userService.delUser(id);
    }
}

/**
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        UserService service = new UserServiceProxy(new UserServiceImpl());
        service.delUser("10002");
    }
}

1.如果只有一个类要记录日志还好,如果有几百个类,像上面这种写法我们需要写几百个代理类,工作量是一方面,类太多而且功能一样也不利于阅读、部署和程序运行(类数量膨胀)。

2.同时上面这种写法在以后扩展也很麻烦,将来又要添加别的操作呢?还要修改很多个类(拓展性差),那么使用JDK的静态代理试试:

完善代码2:修改代理类,修改测试类

 

/**
 * 业务代理类
 */
public class ServiceProxy implements InvocationHandler {
    
    private Object obj;
    
    public ServiceProxy(Object obj){
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("记录日志");
        return method.invoke(obj, args);
    }
}

/**
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserService service = (UserService)Proxy.newProxyInstance(
                Client.class.getClassLoader(),
                userService.getClass().getInterfaces(),
                new ServiceProxy(userService));
        service.delUser("10002");
    }
}

注意看业务代理类,里面没有一个和业务有关的对象,实现了低耦合的目标。

JDK的动态代理既实现了需求同时又很好的解决了类数量膨胀和可拓展性差的问题。即使有再多的类似需求,我们只需要修改一个代理类。

当然JDK动态代理也有不足的地方,从Proxy.newProxyInstance()的参数里不难看出来,它需要被代理的类必须实现某个接口,当然在开发中我们可以解决,比如提供一个什么都不做的接口,但这样做显然不是一个好的主意,特别是在开发框架的时候,我们应该尽可能少的去限制用户。

于是就有了不实现接口就能实现代理的技术,在这里我只列举一种简单的:cglib

扩展demo:无接口类用cglib实现动态代理

/**
 * 用户业务类
 */
public class UserServiceImpl {
    // 删除用户
    public void delUser(String id) {
        System.out.println("这是删除用户" + id + "的操作...");
    }
}

/**
 * 业务代理类
 */
public class CglibProxy implements MethodInterceptor {
    public Object createProxy(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("记录日志");
        return methodProxy.invokeSuper(proxy, args);
    }
}

/**
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        UserServiceImpl service = (UserServiceImpl)proxy.createProxy(UserServiceImpl.class);
        service.delUser("10002");
    }
}

好了,一个工作中的问题让我们完美的解决了(相对完美),不妨从头再捋一遍:

1.写了一个实现业务的类

2.增加大量通用非业务操作,为了代码的高内聚低耦合,模块化开发将非业务通用代码抽离

3.使用静态代理的时候发现工作量很大,同时考虑程序的可扩展性改用JDK动态代理

4.JDK动态代理很优秀的完成了要求,同时发现JDK动态代理需要被代理类实现接口的局限性,使用第三方动态代理技术突破JDK动态代理的局限性

 

 

-------------以下内容可以忽略不看--------------------

JDK动态代理底层用的是反射,cglib用的是字节码生成技术,如果再往下追能追到动态绑定、字节码来源、父类引用指向子类对象、JVM的内存结构、Java编译器、类加载器等等,如果再往上追你就知道Spring的AOP实现用的就是JDK动态代理和cglib,因为知识本身是一个网状结构,找到一个点,就能拉出N多个点,也许这个点是以另一个点为基础,而某些点又是以此为基础。但是知识却又是分层的。比如我会灵活运用代理技术,同时知道各种代理的优缺点,性能上的好坏就足以完成工作,而没有必要非要去研究这个的底层那个的底层,就像厨房的厨师会用冰箱就行了,没必要非要了解冰箱的原理一样。

说了这么多想表达什么呢?第一在我年轻的时候,因为这个走了很多弯路,总是想着去了解底层,才能更好的应用,就投入大量的精力去研究,结果当我这颗小树苗自以为把根扎的足够深抬头准备生长的时候才发现,同期的小树苗,已经长成参天大树,他们没我扎根扎的深,却享受着最多的阳光,疯狂的生长,疯狂的扎根,很快就超过了还在林隙间寻觅阳光我。

还好我明白的早,受用终身。GN:)

Java动态代理浅度分析