您的位置:首页 > 编程语言 > Java开发

java使用动态代理来实现AOP(日志记录)的实例代码

2015-05-07 11:23 1376 查看
AOP(面向方面)的思想,就是把项目共同的那部分功能分离开来,比如日志记录,避免在业务逻辑里面夹杂着跟业务逻辑无关的代码

<iframe id="cproIframe_u1892994_2" width="580" height="90" src="http://pos.baidu.com/acom?adn=3&at=231&aurl=&cad=1&ccd=24&cec=GBK&cfv=17&ch=0&col=zh-CN&conBW=0&conOP=1&cpa=1&dai=2&dis=0&ltr=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DZo87x2oY1aTIV7BqAJF2O_rS8vSjZfTOHAVsD7gTOIOVCfKUzurVEwTbWtwjhHQm%26wd%3Daop%25E7%25BC%2596%25E7%25A8%258B%2520java%2520interface%26issp%3D1%26f%3D3%26ie%3Dutf-8%26tn%3Dbaiduhome_pg%26inputT%3D1561%26oq%3DAOP%25E7%25BC%2596%25E7%25A8%258B%2520%26rsp%3D2&ltu=http%3A%2F%2Fwww.jb51.net%2Farticle%2F41733.htm&lu_161=0&lunum=6&n=jb51_cpr&pcs=1196x557&pis=10000x10000&ps=516x133&psr=1366x768&pss=1196x517&qn=339fe513a5488057&rad=&rsi0=580&rsi1=90&rsi5=4&rss0=%23FFFFFF&rss1=%23F7FCFF&rss2=%230000ff&rss3=%23444444&rss4=%23008000&rss5=&rss6=%23e10900&rss7=&scale=&skin=tabcloud_skin_3&stid=5&td_id=1892994&ti=java%E4%BD%BF%E7%94%A8%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9D%A5%E5%AE%9E%E7%8E%B0AOP(%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95)%E7%9A%84%E5%AE%9E%E4%BE%8B%E4%BB%A3%E7%A0%81_java_%E8%84%9A%E6%9C%AC%E4%B9%8B%E5%AE%B6&titFF=%E5%AE%8B%E4%BD%93&titFS=12&titTA=left&tn=text_default_580_90&tpr=1430969112016&ts=1&version=2.0&xuanting=0&dtm=BAIDU_DUP2_SETJSONADSLOT&dc=2&di=u1892994&tt=1430969111986.2132.2227.2228" align="center,center" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true"></iframe>

下面是一个AOP实现的简单例子:



首先定义一些业务方法:

复制代码代码如下:

/**

 * Created with IntelliJ IDEA.

 * Author: wangjie  email:tiantian.china.2@gmail.com

 * Date: 13-9-23

 * Time: 下午3:49

 */

public interface BussinessService {

    public String login(String username, String password);

    public String find();

}

public class BussinessServiceImpl implements BussinessService {

    private Logger logger = Logger.getLogger(this.getClass().getSimpleName());

    @Override

    public String login(String username, String password) {

        return "login success";

    }

    @Override

    public String find() {

        return "find success";

    }

}

复制代码代码如下:

/**

 * Created with IntelliJ IDEA.

 * Author: wangjie  email:tiantian.china.2@gmail.com

 * Date: 13-9-24

 * Time: 上午10:27

 */

public interface WorkService {

    public String work();

    public String sleep();

}

public class WorkServiceImpl implements WorkService{

    @Override

    public String work() {

        return "work success";

    }

    @Override

    public String sleep() {

        return "sleep success";

    }

}

实现InvocationHandler接口,使用map来存储不同的InvocationHandler对象,避免生成过多。

复制代码代码如下:

package com.wangjie.aoptest2.invohandler;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.Arrays;

import java.util.HashMap;

import java.util.logging.Logger;

/**

 * Created with IntelliJ IDEA.

 * Author: wangjie  email:tiantian.china.2@gmail.com

 * Date: 13-9-23

 * Time: 下午3:47

 */

public class LogInvoHandler implements InvocationHandler{

    private Logger logger = Logger.getLogger(this.getClass().getSimpleName());

    private Object target; // 代理目标

    private Object proxy; // 代理对象

    private static HashMap<Class<?>, LogInvoHandler> invoHandlers = new HashMap<Class<?>, LogInvoHandler>();

    private LogInvoHandler() {

    }

    /**

     * 通过Class来生成动态代理对象Proxy

     * @param clazz

     * @return

     */

    public synchronized static<T> T getProxyInstance(Class<T> clazz){

        LogInvoHandler invoHandler = invoHandlers.get(clazz);

        if(null == invoHandler){

            invoHandler = new LogInvoHandler();

            try {

                T tar = clazz.newInstance();

                invoHandler.setTarget(tar);

                invoHandler.setProxy(Proxy.newProxyInstance(tar.getClass().getClassLoader(),

                        tar.getClass().getInterfaces(), invoHandler));

            } catch (Exception e) {

                e.printStackTrace();

            }

            invoHandlers.put(clazz, invoHandler);

        }

        return (T)invoHandler.getProxy();

    }

    @Override

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

        Object result = method.invoke(target, args); // 执行业务处理

        // 打印日志

        logger.info("____invoke method: " + method.getName()

                    + "; args: " + (null == args ? "null" : Arrays.asList(args).toString())

                    + "; return: " + result);

        return result;

    }

    public Object getTarget() {

        return target;

    }

    public void setTarget(Object target) {

        this.target = target;

    }

    public Object getProxy() {

        return proxy;

    }

    public void setProxy(Object proxy) {

        this.proxy = proxy;

    }

}

然后编写一个Test类测试:

复制代码代码如下:

/**

 * Created with IntelliJ IDEA.

 * Author: wangjie  email:tiantian.china.2@gmail.com

 * Date: 13-9-24

 * Time: 上午9:54

 */

public class Test {

    public static Logger logger = Logger.getLogger(Test.class.getSimpleName());

    public static void main(String[] args) {

        BussinessService bs = LogInvoHandler.getProxyInstance(BussinessServiceImpl.class);

        bs.login("zhangsan", "123456");

        bs.find();

        logger.info("--------------------------------------");

        WorkService ws = LogInvoHandler.getProxyInstance(WorkServiceImpl.class);

        ws.work();

        ws.sleep();

        logger.info("--------------------------------------");

        BussinessService bss = LogInvoHandler.getProxyInstance(BussinessServiceImpl.class);

        bss.login("lisi", "654321");

        bss.find();

    }

}

以后需要添加新的业务逻辑XXXService,只需要调用

XXXService xs = LogInvoHandler.getProxyInstance(XXXServiceImpl.class);

即可。

也可以模仿Spring等框架的配置,把bean的类名配置在xml文件中,如:

<bean id="bussinessService" class="com.wangjie.aoptest2.service.impl.BussinessServiceImpl">

然后在java代码中解析xml,通过Class.forName("com.wangjie.aoptest2.service.impl.BussinessServiceImpl");获得Class对象

然后通过LogInvoHandler.getProxyInstance(Class.forName("com.wangjie.aoptest2.service.impl.BussinessServiceImpl"));获得代理对象Proxy

再使用反射去调用代理对象的方法。

 

运行结果如下:

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: login; args: [zhangsan, 123456]; return: login success

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: find; args: null; return: find success

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.Test main

INFO: --------------------------------------

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: work; args: null; return: work success

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: sleep; args: null; return: sleep success

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.Test main

INFO: --------------------------------------

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: login; args: [lisi, 654321]; return: login success

九月 24, 2013 11:08:03 上午 com.wangjie.aoptest2.invohandler.LogInvoHandler invoke

INFO: ____invoke method: find; args: null; return: find success
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: