1、AOP概念
首先,AOP是对OOP的一个补充。它考虑的是“横切性”问题。横切性问题即可以理解为我们同一层类的问题(例如:Service层)。
它的理念是,把遍历在系统各个角落具有横切性的独立的服务,抽出来放到一个地方,然后等到运行时,再放进去,考虑的是“横向”的东西。将横切性关注的东西给抽出来,会使代码大大减少,更加简洁,更加有复用性。
下图展示AOP中的基本概念:
基础概念不多说,从上图可以看出SpringAOP的实现的过程:
Ø 找到横切性性关注点(发现横切性问题,具体实现为Advice)
Ø 编写切入点(Pointcut),即指定Advice的方法的作用域
Ø 将Advice织入(Weave)目标对象(TargetObject)的Joinpoint
织入(Weave)是动态的,默认采用的方式是JDK的动态代理,当然也可以采用CGLIB代理。
可简单地表示为下图:
2、Spring 对 AOP 的支持—采用Annotation方式
依赖包配置:
*SPRING_HOME/dist/spring.jar
*SPRING_HOME/lib/log4j/log4j-1.2.14.jar
*SPRING_HOME/lib/jakarta-commons/commons-logging.jar
*SPRING_HOME/lib/aspectj/*.jar --(要使用aspectj提供的相关的注解)
源码
interface UserManager
package com.bjpowernode.spring;
public interface UserManager {
public void addUser(String userName, String password);
}
class UserManagerImpl
package com.bjpowernode.spring;
public class UserManagerImpl implements UserManager {
public void addUser(String username, String password) {
System.out.println("---------UserManagerImpl.add()--------");
}
}
*class SecurityHandler(将横切性关注点模块化,建立相关的类)
package com.bjpowernode.spring;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class SecurityHandler {
/**
* 定义Pointcut,Pointcut的名称为addAddMethod(),此方法没有返回值和参数 该方法就是一个标识,不进行调用
*/
@Pointcut("execution(* add*(..))")
private void addAddMethod() {
};
/**
* 定义Advice,表示我们的Advice应用到哪些Pointcut订阅的Joinpoint上
*/
@Before("addAddMethod()")
// @After("addAddMethod()")
private void checkSecurity() {
System.out.println("");
System.out.println("-------checkSecurity-------");
}
}
为所有的方法名中带add的方法,执行之前都加入checkSecurity()服务。
Spring配置文件—ApplicationContext.xml
<?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">
<!-- 启用AspectJ对Annotation的支持 -->
<aop:aspectj-autoproxy/>
<bean id="userManager" class="com.bjpowernode.spring.UserManagerImpl"/>
<bean id="securityHandler" class="com.bjpowernode.spring.SecurityHandler"/>
</beans>
classClient—客户端
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");
System.out.print(factory);
UserManager userManager = (UserManager) factory.getBean("userManager");
userManager.addUser("张三", "123");
}
}
运行结果:
-------checkSecurity-------
---------UserManagerImpl.add()--------
3、Spring 对 AOP 的支持—采用"配置文件"方式
与上面实现相同的效果。
* 依赖包配置采用上面的“采用Annotation方式”即可
* 直接看源码:
interface UserManager与上面相同
class UserManagerImpl与上面相同
class SecurityHandler(将横切性关注点模块化,建立相关的类):
package com.bjpowernode.spring;
public class SecurityHandler {
private void checkSecurity() {
System.out.println("");
System.out.println("-------checkSecurity-------");
}
}
*Spring配置文件—ApplicationContext.xml
<?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.*.*(..))"/>
-->
<!-- com.bjpowernode.spring包下所有类的所有add与del方法 -->
<aop:pointcut id="addAddMethod" expression="execution(* com.bjpowernode.spring.*.add*(..))||execution(* com.bjpowernode.spring.*.del*(..))"/>
<!-- Advice,配一个Pointcut -->
<aop:before method="checkSecurity" pointcut-ref="addAddMethod"/>
</aop:aspect>
</aop:config>
</beans>
主要是在aspect节中,将Advice与Poincut联系起来
classClient—客户端也与上面相同
运行结果正确:
-------checkSecurity-------
---------UserManagerImpl.add()--------
4、总结
做AOP,重点是,发现Aspect(切面),并在“运行时”切入进去。织入过程,默认采用JDK的动态代理。动态灵活,但比较慢;静态比较快(可以预编译),但不灵活。Spring的AOP可以针对pojo对象提供声明式服务,如声明式事务; Ejb里面的SessionBean也可以提供声明式事务。