代码如下:
public static class LoginCheckHandler implements InvocationHandler {
private static <S, T extends S> T proxy(S source, Class tClass) {
return (T) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{tClass}, new LoginCheckHandler(source));
}
private Object mSource;
LoginCheckHandler(Object source) {
this.mSource = source;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(!checkLogin()){
jumpToLoginActivity();
return null;
}
return method.invoke(mSource, args);
}
private boolean checkLogin(){
System.out.println(“用户未登录”);
return false;
}
private void jumpToLoginActivity(){
System.out.println(“跳转到登录页”);
}
}
public class Client {
public static void main(String[] args) {
IUserSetting source = new UserSetting();
IUserSetting iUserSetting = LoginCheckHandler.proxy(source,IUserSetting.class);
iUserSetting.changePwd(“new Password”);
}
}
经过这样封装之后,检查登录跳转登录页的逻辑作为横切关注点就和业务主体进行了分离。当有新的需求需要登录检查时,我们只需要通过LoginCheckHandler生成新的代理对象即可。
APT
APT(Annotation Processing Tool)是一种编译期注解处理技术。它通过定义注解和处理器来实现编译期生成代码的功能,并且将生成的代码和源代码一起编译成.class文件。通过APT技术,我们将横切关注点封装到注解处理器中,从而实现横切关注点与业务主体的分离。更详细的介绍请移步Android编译期插桩,让程序自己写代码(一)。
AspectJ
AspectJ就是一种编译器,它在Java编译器的基础上增加了关键字识别和编译方法。因此,AspectJ可以编译Java代码。它还提供了Aspect程序。在编译期间,将开发者编写的Aspect程序织入到目标程序中,扩展目标程序的功能。开发者通过编写AspectJ程序实现AOP功能。更详细的介绍请移步Android编译期插桩,让程序自己写代码(二)。
Transform + Javassist/ASM
Transform是Android Gradle提供的,可以操作字节码的一种方式。App编译时,源代码首先会被编译成class,然后再被编译成dex。在class编译成dex的过程中,会经过一系列Transform处理。Javassist/ASM是一个能够非常方便操作字节码的库。我们通过它们可以修改编译的.class文件。利用这种方式,我们将横切关注点封装到Transform,来达到与业务主体分离的目的。更详细的介绍请移步Android编译期插桩,让程序自己写代码(三)。
我们可以用来实现什么功能?
利用AOP可以做一些很有意思的事情。一些知名的开源框架,他们都采用了AOP的思想。例如:ButterKnife、Retrofit、Hugo等。另外,AOP在性能检测和埋点技术上出现了百家争鸣的局面。
-
性能检测与优化。360的ArgusAPM、滴滴的booster、Jake Wharton大神的Hugo。
-
埋点技术。罗辑思维的DDAutoTracker、神策数据的Sensors Analytics、网易的HubbleData等。
除此之外,借助AOP我们还可以实现以下功能:
-
通常我们在向服务器请求数据时,会显示一个Loding,等到结果返回后再隐藏它。我们可以通过AOP技术把显示、隐藏Loding的动作和业务主体分离开。
-
权限管理。给大家推荐一个开源库Aopermission,用AspectJ解决了权限问题。