AOP实现原理——动态代理

      前几天阿里面试问AOP是怎么实现的,感觉自己当时答的不好,于是回来重新研究了一下,找了下资料,现在来做个分享.
      Spring两大核心IOC与AOP.IOC负责将对象动态的注入到容器,让容器来管理bean,AOP就是可以让容器中的对象都享有容器中的公共服务(如日志记录等等).那么AOP是怎么实现的,下面讲一下我的理解——动态代理。
      动态代理就是利用反射和动态编译将代理模式变成动态的.原理跟动态注入一样,代理模式在编译的时候就已经确定代理类将要代理谁,而动态代理在运行的时候才知道自己要代理谁。下面看代码:

假设我们要对下面这个用户管理类进行代理:

package com.kevindai.AOP;

public interface UserService {
    /**
     * 
      * @Title: addUser
      * @Description: 增加user
      * @param   
      * @author kevindai
      * @return void    返回类型
      * @throws
     */
    public void addUser();
    /**
     * 
      * @Title: delUser
      * @Description: 删除user
      * @param   
      * @author kevindai
      * @return void    返回类型
      * @throws
     */
    public void delUser();
    /**
     * 
      * @Title: updateUser
      * @Description: 修改user
      * @param   
      * @author kevindai
      * @return void    返回类型
      * @throws
     */
    public void updateUser();
}
package com.kevindai.AOP;

public class UserServiceImpl implements UserService {
    /**
     * 
      * @Title: addUser
      * @Description: 增加User
      * @param   
      * @author kevindai
      * @return 
      * @throws
     */
    public void addUser() {
        System.out.println("addUser....");
    }
    /**
     * 
      * @Title: delUser
      * @Description: 删除User
      * @param   
      * @author kevindai
      * @return 
      * @throws
     */
    public void delUser() {
        System.out.println("delUser....");

    }
    /**
     * 
      * @Title: updateUser
      * @Description: 删除User
      * @param   
      * @author kevindai
      * @return 
      * @throws
     */
    public void updateUser() {
        System.out.println("updateUser....");

    }

}

按照代理模式的实现方式,一般是用一个代理类,让它也实现UserService接口,然后在其内部声明一个UserServiceImpl,然后分别调用addUser和delUser等方法,并在调用前后加上我们需要的其他操作。但是这样都是写死的,不能做到动态呢。要实现代理,那么代理类跟被代理类都要实现同一接口,但是动态代理的话根本不知道我们将要代理谁,也就不知道要实现哪个接口。这时候就应该动态生成代理类!
来来一个方法来接收被代理类,这样我们就可以通过反射知道它的信息。

package com.kevindai.AOP;

import java.lang.reflect.Method;

public interface InvocationService {
    public void invoke(Object o, Method m);
}

实现动态代理的关键部分,通过Proxy动态生成我们具体的代理类:

package com.kevindai.AOP;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

/**
 * 
* @ClassName: Proxy
* @Description: 通过动态代理实现AOP
* @author kevindai
* @date 2016-3-31 下午3:56:58
*
 */
public class Proxy {
    /**
     * 
      * @Title: proxyInterface
      * @Description: TODO(这里用一句话描述这个方法的作用)
      * @param @param 传入的接口
      * @param @param 代理类
      * @param @return  
      * @author kevindai
      * @return Object    返回类型
      * @throws
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static Object proxyInterface(Class clazz,InvocationService invo) throws Exception{
        StringBuffer method = new StringBuffer();
        String br = "\r\n";

        Method[] methods = clazz.getMethods();
        for(Method m : methods){
            method
            //.append(" @Override").append(br)
            .append("   public ").append(m.getReturnType()).append(" ").append(m.getName()).append("(){").append(br)
            .append("       try{").append(br)
            .append("               Method md = ").append(clazz.getName()).append(".class.getMethod(\"").append(m.getName()).append("\");").append(br)
            .append("               invo.invoke(this,md);").append(br)
            .append("           }catch(Exception e){e.printStackTrace();}").append(br)
            .append("   }").append(br).append(br);
        }
        //根据要代理的方法信息来生成java源文件
        StringBuffer codeSrc = new StringBuffer();
        codeSrc.append("package com.kevindai.AOP;").append(br)
                .append("import java.lang.reflect.Method;").append(br)
                .append("public class $Proxy1 implements ").append(clazz.getName()).append("{").append(br)
                .append("   public $Proxy1(InvocationService invo){").append(br)
                .append("       this.invo = invo;").append(br)
                .append("   }").append(br)
                .append("   com.kevindai.AOP.InvocationService invo;").append(br)
                .append(method).append(br)
                .append("}");
        String fileName = "C:/myeclipse/starsinoWs/Test/src/com/kevindai/AOP/$Proxy1.java";
        File f = new File(fileName);  
        FileWriter fw = new FileWriter(f);  
        fw.write(codeSrc.toString());  
        fw.flush();  
        fw.close();

        //将Java文件编译成class文件  
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();  
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);  
        Iterable units = fileMgr.getJavaFileObjects(fileName);  
        CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);  
        t.call();  
        fileMgr.close();  

        //加载到内存,并实例化  
        URL[] urls = new URL[] {new URL("file:/" + "C:/myeclipse/starsinoWs/Test/src/")};  
        URLClassLoader ul = new URLClassLoader(urls);  
        Class c = ul.loadClass("com.kevindai.AOP.$Proxy1");  

        Constructor ctr = c.getConstructor(InvocationService.class);  
        Object m = ctr.newInstance(invo);  

        return m;  
    }
}

这个类的主要功能就是,根据被代理对象的信息,动态组装一个代理类,生成 Proxy1.java Proxy1.class。这样就可以在运行的时候,根据具体的被代理对象生成需要的代理类了。这样一来,就算不知道需要代理谁,也能生成相应的代理类。

然后写一些代理信息,我这里写的是事务和时间:

package com.kevindai.AOP;

import java.lang.reflect.Method;

public class TransactionService implements InvocationService {  

    private Object target;  

    public TransactionService(Object target) {  
        super();  
        this.target = target;  
    }  

    public void invoke(Object o, Method m) {  
        System.out.println("开启事务.....");  
        try {  
            m.invoke(target);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        System.out.println("提交事务.....");  
    }  

} 
package com.kevindai.AOP;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeService implements InvocationService {

    private Object target;  

    public TimeService(Object target) {  
        super();  
        this.target = target;  
    }


    public void invoke(Object o, Method m) {  
        System.out.println("开始时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E").format(new Date()));  
        try {  
            m.invoke(target);  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        System.out.println("开始时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E").format(new Date()));  
    }  
}

现在开始测试一下:

package com.kevindai.AOP;


public class Test {
    public static void main(String[] args) throws Exception {
        UserService userService = new UserServiceImpl();  

        //为用户管理添加事务处理  
        InvocationService h = new TransactionService(userService);  
        UserService u = (UserService)Proxy.proxyInterface(UserService.class,h);  

        //为用户管理添加显示方法执行时间的功能  
        TimeService h2 = new TimeService(u);  
        u = (UserService)Proxy.proxyInterface(UserService.class,h2);  

        u.addUser();  
        System.out.println("\r\n==================================\r\n");  
        u.delUser();  
    }
}

看看输出:

开始时间:2016-03-31 17:48:23 星期四
开启事务.....
addUser....
提交事务.....
开始时间:2016-03-31 17:48:23 星期四

==================================

开始时间:2016-03-31 17:48:23 星期四
开启事务.....
delUser....
提交事务.....
开始时间:2016-03-31 17:48:23 星期四

OK,动态代理完成,这也就是AOP的实现方式。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值