网上不少人在介绍AOP时都这样说:面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。我的认为这句话是错误。AOP和OOP同样,是一种程序设计思想,而非技术手段。javascript
程序设计有六大原则,其中第一原则就是单一职责原则。意思就是一个类只负责一件事情。这与OOP的封装特性相得益彰。在这个条件下,咱们的程序会被分散到不一样的类、不一样的方法中去。这样作的好处是下降了类的复杂性,提升了程序的可维护性。可是同时,它也使代码变得啰嗦了。例如,咱们要为方法添加调用日志,那就必须为全部类的全部方法添加日志调用,尽管它们都是相同的。为了解决上述问题,AOP应运而生了。html
AOP旨在将横切关注点与业务主体进行分类,从而提升程序代码的模块化程度。横切关注点是一个抽象的概念,它是指那些在项目中贯穿多个模块的业务。上个例子中日志功能就是一个典型的横切关注点。java
动态代理是一种设计模式。它有如下特征:android
如下面这个例子为例,咱们看一下动态代理的类图结构。git
一般咱们的APP都有一部分功能要求用户登陆以后才能访问。如修改密码、修改用户名等功能。当用户打算使用这些功能时,咱们通常要对用户的登陆状态进行判断,只有用户登陆了,才能正常使用这些功能。而若是用户未登陆,咱们的APP要跳转到登陆页。就以修改密码为例咱们看一下动态代理的类图。github
InvocationHandler是Java JDK提供的动态代理的入口,用来对被代理对象的方法作处理。编程
代码以下:设计模式
public static class LoginCheckHandler implements InvocationHandler {
private static <S, T extends S> T proxy(S source, Class<T> 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生成新的代理对象便可。api
APT(Annotation Processing Tool)是一种编译期注解处理技术。它经过定义注解和处理器来实现编译期生成代码的功能,而且将生成的代码和源代码一块儿编译成.class文件。经过APT技术,咱们将横切关注点封装到注解处理器中,从而实现横切关注点与业务主体的分离。更详细的介绍请移步Android编译期插桩,让程序本身写代码(一)。服务器
AspectJ就是一种编译器,它在Java编译器的基础上增长了关键字识别和编译方法。所以,AspectJ能够编译Java代码。它还提供了Aspect程序。在编译期间,将开发者编写的Aspect程序织入到目标程序中,扩展目标程序的功能。开发者经过编写AspectJ程序实现AOP功能。更详细的介绍请移步Android编译期插桩,让程序本身写代码(二)。
Transform是Android Gradle提供的,能够操做字节码的一种方式。App编译时,源代码首先会被编译成class,而后再被编译成dex。在class编译成dex的过程当中,会通过一系列Transform
处理。Javassist/ASM是一个可以很是方便操做字节码的库。咱们经过它们能够修改编译的.class文件。利用这种方式,咱们将横切关注点封装到Transform,来达到与业务主体分离的目的。更详细的介绍请移步Android编译期插桩,让程序本身写代码(三)。
利用AOP能够作一些颇有意思的事情。一些知名的开源框架,他们都采用了AOP的思想。例如:ButterKnife、Retrofit、Hugo等。另外,AOP在性能检测和埋点技术上出现了百家争鸣的局面。
除此以外,借助AOP咱们还能够实现如下功能:
一般咱们在向服务器请求数据时,会显示一个Loding,等到结果返回后再隐藏它。咱们能够经过AOP技术把显示、隐藏Loding的动做和业务主体分离开。
权限管理。给你们推荐一个开源库Aopermission,用AspectJ解决了权限问题。