上篇谈到了IOC,这篇主要谈谈AOP的基本概念和理解。
AOP是什么
AOP(Aspect-Oriented Programming,面向方面编程)。方面(Aspect),我理解为与业务无关,却为业务提供公共服务的模块。我们把AOP看做是OOP的一种补充和完善。这里AOP是一种编程思想,但是我们做讨论时不区分那么清楚,说AOP,大家都不约而同地理解为AOP技术。
AOP技术是一种横切性技术,它把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP中涉及到的概念
我们先看一张图:
Cross Cutting Concern:就是上面提到的横切关注点,是一种独立服务,它会遍布在系统的处理流程之中。
Aspect:对横切性关注点的模块化
Advice:对横切性关注点的具体实现
Pointcut:它定义了Advice应用到哪些JoinPoint上,对Spring来说是方法调用
JoinPoint:Advice在应用程序上执行的点或时机,Spring只支持方法的JoinPoint,这个点也可以使属性修改,如:Aspecj可以支持
Advice类型:
Before advice:在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
After advice:当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext中在<aop:aspect>里面使用<aop:after>元素进行声明。
After returnadvice:在某连接点正常完成后执行的通知,不包括抛出异常的情况。
Around advice:包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext中在<aop:aspect>里面使用<aop:around>元素进行声明。
Afterthrowing advice:在方法抛出异常退出时执行的通知。 ApplicationContext中在<aop:aspect>里面使用<aop:after-throwing>元素进行声明。
切入表达式:常情况下,表达式中使用”execution“就可以满足大部分的要求。比如:com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法的表达式为:
execution(* com.bjpowernode.spring.*.*(..))
AOP的使用
SecurityHandler.java:
package com.bjpowernode.spring;
public class SecurityHandler {
private void checkSecurity() {
System.out.println("-------checkSecurity-------");
}
}
UserManager.java
package com.bjpowernode.spring;
public interface UserManager {
public void addUser(String username, String password);
public void delUser(int userId);
public String findUserById(int userId);
public void modifyUser(int userId, String username, String password);
}
UserManagerImpl.java
package com.bjpowernode.spring;
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
//checkSecurity();
System.out.println("---------UserManagerImpl.add()--------");
}
public void delUser(int userId) {
//checkSecurity();
System.out.println("---------UserManagerImpl.delUser()--------");
}
public String findUserById(int userId) {
//checkSecurity();
System.out.println("---------UserManagerImpl.findUserById()--------");
return "张三";
}
public void modifyUser(int userId, String username, String password) {
//checkSecurity();
System.out.println("---------UserManagerImpl.modifyUser()--------");
}
}
Client.java
package com.bjpowernode.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Client {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");
userManager.delUser(1);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="userManager" class="com.bjpowernode.spring.UserManagerImpl"/>
<bean id="securityHandler" class="com.bjpowernode.spring.SecurityHandler"/>
<aop:config>
<aop:aspect id="securityAspect" ref="securityHandler">
<!--
以add开头的方法
<aop:pointcut id="addAddMethod" expression="execution(* add*(..))"/>
-->
<!--
com.bjpowernode.spring包下所有的类所有的方法
<aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.*(..))"/>
-->
<aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.add*(..)) || execution(* com.bjpowernode.spring.*.del*(..))"/>
<aop:before method="checkSecurity" pointcut-ref="addAddMethod"/>
</aop:aspect>
</aop:config>
</beans>
运行结果:
总结:AOP的核心就是核心关注点和横切关注点分离开来。