Nemo

Nemo 关注TA

路漫漫其修远兮,吾将上下而求索。

Nemo

Nemo

关注TA

路漫漫其修远兮,吾将上下而求索。

  •  普罗旺斯
  • 负责帅就完事了
  • 写了1,496,113字

该文章投稿至Nemo社区   Java  板块 复制链接


JAVA-动态代理实现AOP原理简单探索

发布于 2017/12/22 15:18 3,647浏览 0回复 2,661

假设这样一个场景:

    当我们在调用某些方法的时候,需要在调用方法前后,记录执行日志。

    简单的做法肯定是在原业务方法的前后作修改,添加记录日志的代码。不过这肯定存在一些问题,比如,当你要记录日志的方法很多,或者偶尔需要修改记录日志的方法,等等。所以需要考虑在不对原有的业务方法产生影响的情况下,加入日志记录。

    举个栗子说明下好了:


首先,定义一个业务接口类,一个业务实现类:

/**
* 业务接口类
* Created by Nemo on 2017/12/22.
*/
public interface IBusiness {

boolean doSomeThing() ;

}
/**
* 业务实现类
* Created by Nemo on 2017/12/22.
*/
public class Business implements IBusiness {

LogUtils log = LogUtils.getLog(Business.class);

public boolean doSomeThing() {
log.debug("这是一个业务逻辑。");
return true;
}

}


然后一般的做法:

/**
* 业务实现类
* Created by Nemo on 2017/12/22.
*/
public class Business implements IBusiness {

LogUtils log = LogUtils.getLog(Business.class);

public boolean doSomeThing() {
log.debug("开始记录日志。");
log.debug("这是一个业务逻辑。");
log.debug("记录日志结束。");
return true;
}

}


再看动态代理的实现:

咱们需要一个记录日志的切面类:

import com.nemo.framework.dao.utils.LogUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
* 打印日志的切面
* Created by Nemo on 2017/12/22.
*/
public class LogInvocationHandler implements InvocationHandler {

LogUtils log = LogUtils.getLog(LogInvocationHandler.class);

private Object target; //目标对象

LogInvocationHandler(Object target) {
this.target = target;
}

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

log.debug("方法执行前记录日志。");

//执行原有逻辑
Object rev = method.invoke(target, args);

log.debug("方法执行后记录日志。");

return rev;
}
}


然后测试调用:

/**
* Created by Nemo on 2017/12/22.
*/
public class ProxyTest {

public static void main(String[] args) {
IBusiness business = (IBusiness) getProxyInstence(IBusiness.class,new Business());
business.doSomeThing();
}

/**
* 得到被代理的对象
* @param clazz
* @param instence
* @return
*/
private static Object getProxyInstence(Class clazz,Object instence){
//需要代理的接口,被代理类实现的多个接口都必须在这里定义
Class[] proxyInterface = new Class[] { clazz };
//构建AOPAdvice,这里需要传入业务类的实例
LogInvocationHandler handler = new LogInvocationHandler(instence);
//生成代理类的字节码加载器
ClassLoader classLoader = ProxyTest.class.getClassLoader();
//织入器,织入代码并生成代理类
Object proxyBusiness = Proxy.newProxyInstance(classLoader, proxyInterface, handler);
//使用代理类的实例来调用方法。
return proxyBusiness;
}

}


可以看到,这里只需在调用的地方传入类定义以及实例,即可得到被代理的对象。然后强制转型,即可以调用相应的业务方法。

并且,在不破坏原来业务逻辑的前提下,日志由咱们的业务日志切面处理即可。

不过,弊端也是有的:

IBusiness business = (IBusiness) getProxyInstence(IBusiness.class,new Business());

可以看到,我们这里还是new Business()了。也就是说,目前暂时不能代理没有实现业务的接口类。

所以还需要解决下没有实现业务的接口类代理问题。

本文标签
 {{tag}}
点了个评