【转】动态代理实现AOP

  今天说和小张哥一起讨论AOP,正好看到了相关的视频,今天就总结一下AOP是如何使用动态代理来实现的。
  AOP对JAVA程序员来说并不陌生,他是spring的一个核心内容——面向切面编程,先把概念放在这里,因为这一篇博客不会展开讲述AOP是什么,而是讲一讲他的来源——动态代理。我们先来看一个例子:有一个接口:UserManager,还有就是接口的实现类UserManagerImpl
UserManager

public interface UserManager {

    public void addUser(String username, String password);

    public void delUser(int userId);

    public String findUserById(int userId);

    public void modifyUser(int userId, String username, String password);
}

UserManagerImpl

public class UserManagerImpl implements UserManager {

    public void addUser(String username, String password) {
        System.out.println("---------UserManagerImpl.add()--------");
    }

    public void delUser(int userId) {
        System.out.println("---------UserManagerImpl.delUser()--------");
    }

    public String findUserById(int userId) {
        System.out.println("---------UserManagerImpl.findUserById()--------");
        return "张三";
    }

    public void modifyUser(int userId, String username, String password) {
        System.out.println("---------UserManagerImpl.modifyUser()--------");
    }
}

 如果现在我们要添加安全性检查,在每执行代码之前,都加入安全性检查,那么我们就要打开已经写好的接口实现类,进行修改:

//安全性检查
    private void checkSecurity() {
        System.out.println("-------checkSecurity-------");
    }
    public void addUser(String username, String password) {
        checkSecurity();
        System.out.println("---------UserManagerImpl.add()--------");

。。。。。//别的方法不在赘述
    }     

  这样做我们发现不但违反了开闭原则,而且相同的方法调用到处都是,代码十分冗余,一直在“重复自己”,代码变得一点也不干净(dry:dont repeat yourself!!!),如何解决这两个问题呢??
  我们想到了使用代理模式,还记得第一次看大话设计模式,代理模式就是一个男孩子帮“小菜”追女孩儿,他不好意思做的事情,让代理帮他去做,从而达到解耦的功效,但是代理不能修改实际的方法,只起到控制的作用。接下来我们来修改上边这段代码:创建UserManager的代理类:UserManagerImplProxy

public class UserManagerImplProxy implements UserManager {

    private UserManagerImpl userManagerImpl;

    public UserManagerImplProxy(UserManagerImpl userManagerImpl) {
        this.userManagerImpl= userManagerImpl;
    }

    public void addUser(String username, String password) {
        checkSecurity();
        userManagerImpl.addUser(username, password);
    }

    public void delUser(int userId) {
        checkSecurity();
        userManagerImpl.delUser(userId);
    }

    public String findUserById(int userId) {
        checkSecurity();
        return userManagerImpl.findUserById(userId);
    }

    public void modifyUser(int userId, String username, String password) {
        checkSecurity();
        userManagerImpl.modifyUser(userId, username, password);
    }

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

创建好了之后,我们发现如果想要让客户端调用添加用户的方法,就要通过调用代理类的addUser,如下:

public void addUser(String username, String password) {
        checkSecurity();//实现安全性检查
        userManagerImpl.addUser(username, password);
    }      

  通过代理类,我们就不需要对写好的接口实现类进行修改了,但是这样做依然没有解决checkSecurity方法到处出现的问题,因为静态代理是一对一的关系,也就是有一个接口,就对应有一个代理类,解决这个问题就需要使用动态代理(上边是通过静态代理实现的),我们只需要创建一个代理类,它就可以在运行时给我们想要的方法,动态代理的实现应用到了反射

  首先我们要创建一个SecurityHandler(可以把他理解为创建代理的工厂,你要什么样的代理,这个类就能在运行的时候给你什么样的代理):
首先这个类要实现 InvocationHandler, 然后我们定义一个产生代理实例的方法:createProxyInstance

//定义一个私有成员:目标对象
    private Object targetObject;
//产生代理对象
    public Object createProxyInstance(Object targetObject) {
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 
                               targetObject.getClass().getInterfaces(), 
                               this);
    }   

这个方法其实实现了java.lang.reflect.Proxy中的Proxy类的静态方法:newProxyInstance(具体实现过程看下边的解析),说白了就是你丢进来一个UserManager的接口,他就能返回一个实现了我UserManager接口所有方法的代理类

动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组);然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员。 初始化之后将对象返回给调用的客户端。这样客户端拿到的就是一个实现你所有的接口的Proxy对象。

  接着我们来看看checkSecurity写在哪里,我们在写一个invoke方法,这个方法实现了InvocationHandler接口的invoke方法,这个类就是最终Proxy调用的固定的接口的方法。Proxy不管客户端的业务方法是如何实现的,当客户端调用Proxy时,他只会调用InvocationHandler的invoke接口,所以我们的安全性检查只能放到invoke方法中

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        checkSecurity();

        //调用目标方法
        Object ret = method.invoke(targetObject, args);

        return ret;
    }

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

客户端代码:

public class Client {

    public static void main(String[] args) {
        SecurityHandler hander = new SecurityHandler();
        UserManager useraManager = (UserManager)hander.createProxyInstance(new UserManagerImpl());
        useraManager.addUser("张三", "123");
    }

}     

结果输出:
这里写图片描述

至于对类Proxy的深入理解,我参考了:http://blog.csdn.net/rokii/article/details/4046098(深入理解Java Proxy机制)这篇博客,博主自己写了两个静态的方法,可以对Proxy一探究竟,有兴趣的朋友可以去了解一下

that’s all!

猜你喜欢

转载自blog.csdn.net/u013870094/article/details/81055877
今日推荐