AOP是英文Aspect Oriented Programming的缩写,也就是面向切面编程。Java最重要的思想就是面向对象的编程思想,万物皆对象,面向切面编程与之恰好是互补的关系,其中OOP理解为纵向编程,而AOP是横向编程。
我们在设计对象的时候一般都是纵向思维,如果这个时候考虑这些不同类对象的共性,不仅会增加设计的难度和复杂性,还会造成类的接口过多而难以维护,以至于对现有的对象动态增加一些方法的时候就会非常困难。这个时候,就需要用上AOP了。AOP就可以很好地解决以上的问题,它除了这种纵向分类之外,还从横向的角度去观察这些对象,无需再去到处调用 LogUtils 了,声明哪些地方需要打印日志,这个地方就是一个切面,AOP 会在适当的时机为你把打印语句插进切面。
系统之间在进行接口调用时,往往是有入参传递的,入参是接口业务逻辑实现的先决条件,有时入参的缺失或错误会导致业务逻辑的异常,大量的异常捕获无疑增加了接口实现的复杂度,也让代码显得雍肿冗长,因此提前对入参进行验证是有必要的,可以提前处理入参数据的异常,并封装好异常转化成结果对象返回给调用方,也让业务逻辑解耦变得独立。
避免到处都是申请权限和处理权限的代码
所谓的”无痕埋点”,其实就是通过技术手段,无差别的记录用户在产品中的行为
比如全局的登录状态流程控制。
日志记录
事件防抖
防止View被连续点击触发多次事件
检测方法耗时其实已经有一些现成的工具,比如 trace view。痛点是这些工具使用起来都比较麻烦,效率低下,而且无法针对某一个块代码或者某个指定的sdk进行查看方法耗时。可以采用 AOP 思想对每个方法做一个切点,在执行之后打印方法耗时。
声明方法,为特定方法加上事务,指定情况下(比如抛出异常)回滚事务
替代防御性的 try-Catch。
缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
使用修改软件的验证类的判断逻辑。
AOP 可以让我们在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
public class UserServiceImpl implements UserService {
private UsersDao usersDao;
public void setUsersDao(UsersDao usersDao) {
System.out.println("setUsersDao");
this.usersDao = usersDao;
}
public int insetrUser1(Users users) {
System.out.println("UserServiceImpl");
usersDao.insetrUser1(users);
return 0;
}
}
多种advice
前置额外功能:MethodBeforeAdvice 。前置额外功能会在目标核心功能执行之前执行
public void before(JoinPoint joinPoint){
System.out.println("日志开始");
System.out.println(new Date()+"切点对象信息:"+joinPoint.getTarget().getClass().getSimpleName());
System.out.println("方法信息:"+joinPoint.getSignature());
System.out.println("参数信息:"+joinPoint.getArgs());
}
<bean id="myaop" class="com.xzk.Util.MyAop"></bean>
<aop:config>
<aop:pointcut id="mypc" expression="execution(public void com.xzk.service.UserService.insetrUser1())"/>
<aop:aspect ref="myaop">
<!--写入需要增强的方法-->
<aop:before method="before" pointcut-ref="mypc"/>
</aop:aspect>
</aop:config>
后置额外功能:AfterReturningAdvice。后置额外功能会在目标核心功能执行之后执行
public void after(){
System.out.println("日志结束");
}
------------------------------------------------------------------------
<bean id="myaop" class="com.xzk.Util.MyAop"></bean>
<aop:config>
<aop:pointcut id="mypc" expression="execution(public void com.xzk.service.UserService.insetrUser1())"/>
<aop:aspect ref="myaop">
<!--写入需要增强的方法-->
<aop:after-returning method="after" pointcut-ref="mypc"/>
</aop:aspect>
</aop:config>
环绕额外对象:MethodInterceptor。环绕额外功能会在目标核心功能执行前后都执行
public void myaroud(ProceedingJoinPoint joinPoint){
System.out.println("环绕开始");
try {
joinPoint.proceed(); //调取目标方法
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("环绕结束");
}
------------------------------------------------------------------------
<aop:around method="myaroud" pointcut-ref="mypc"/>
异常额外对象:ThrowAdvice。前置额外功能会在目标核心功能执行之前执行(相当于try…catch)
public void myex(){
System.out.println("异常增强");
}
------------------------------------------------------------------------
<aop:after-throwing method="myex" pointcut-ref="mypc"/>
最终额外对象:在核心执行之后(即使核心出现了异常,依然执行额外,相当于try…catch…finally中的finally)。后置额外功能会在目标核心功能执行之后执行
public void aftera(){
System.out.println("最终增强");
}
------------------------------------------------------------------------
<aop:after method="aftera" pointcut-ref="mypc"/>
所谓编织,即,将Target和Advice组装形成代理,整个组装过程由Spring来管理,我们只需要做出配置,告知Spring需要组装谁即可
<!-- id="(唯一的)对象名" class="类的完整路径"-->
<bean id="udao" class="com.xzk.dao.impl.UserDaoImpl"></bean>
<bean id="uservice" class="com.xzk.service.impl.UserServiceImpl">
<property name="usersDao" ref="udao"></property>
</bean>
<bean class="com.xzk.bean.Users" p:users="馒头"></bean>
编写一个测试类
public static void main(String[] args) {
// 1.加载配置文件
ApplicationContext app = new ClassPathXmlApplicationContext("application.xml");
// 2.通过getBean获得指定对象
UserService uservice = (UserService) app.getBean("uservice");
uservice.insetrUser1(new Users());
}