一、SpringAOP 简介
1.AOP思想:
AOP即面向切面编程,可以说是OOP的补充和完善。它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。
所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
2.AOP概念:
1)AOP把软件系统分为两个部分:核心关注点和横切关注点。
业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如设置页面编码、权限认证、日志、事务。
AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
3.AOP使用
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
- 1)定义普通业务组件
- 2)定义切入点,一个切入点可能横切多个业务组件
- 3)定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点(在哪里要添加方法)和定义增强处理(要添加的方法),一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。
4.AOP概念:
横切关注点:对那些方法进行拦截,拦截后怎么处理,类似这些的关注点
切面(次要业务):是对横向关注点的抽象<aop:aspect>
连接点(所有可能进行切面操作的方法即类中的所有方法):被拦截到的点,因为Spring只支持方法类型的连接点不能操作属性和构造方法,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
切入点(具体拦截到的方法):对连接点进行拦截的定义<aop:pointer>
通知:所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
目标对象:代理的目标对象
织入(weave):(在原有的方法织入一个新的方法形成一个大方法)将切面应用到目标对象并导致代理对象创建的过程
将切面的通知方法织入到切点方法的过程
5.Spring 对AOP的支持:
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。
<aop:config>
<aop:aspect id="time" ref="timeHandler"><>
<aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
<aop:before method="printTime" pointcut-ref="addAllMethod" />
<aop:after method="printTime" pointcut-ref="addAllMethod" />
</aop:aspect>
</aop:config>
二、SringAOP简单例子--方法执行前打印当前时间
1.pom.xml
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>
2.业务逻辑
核心关注点(主要业务--打印Hello World!)
//接口
package org.lanqiao.aop;
public interface Hello {
void print();
}
//实现类
package org.lanqiao.aop;
public class HelloImpl implements Hello {
public void print() {
System.out.println("Hello World!");
}
}
横切关注点(次要业务--打印当前时间)
package org.lanqiao.aop;
public interface TimeAOP {
void printTime();
}
package org.lanqiao.aop;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TimeAOPImpl implements TimeAOP {
@Override
public void printTime() {
long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
Date date = new Date(currentTime);
System.out.println(formatter.format(date));
}
}
3.Spring配置文件aop.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="hello" class="org.lanqiao.aop.HelloImpl"/>
<bean id="timeHander" class="org.lanqiao.aop.TimeAOPImpl"/>
<aop:config><!--横切关注点,对哪些方法进行拦截,拦截后怎么处理-->
<aop:aspect id="timeAspect" ref="timeHander"><!--定义切面 若有多个切面可通过执行顺序 order="1"等控制顺序或者上下文顺序 -->
<aop:pointcut id="helloPointcut" expression="execution(* org.lanqiao.aop.Hello.*(..))"/><!--定义切入点-->
<aop:before method="printTime" pointcut-ref="helloPointcut"/><!--将通知织入到切入点-->
<!--<aop:around method="printTime" pointcut-ref="helloPointcut"/>-->
</aop:aspect>
</aop:config>
</beans>
常见切入点表达式的例子:
任意公共方法的执行:
execution(public * *(..))任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService
接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))定义在service包或者子包里的任意类的任意方法的执行:
execution(* com.xyz.service..*.*(..))
4.测试
package org.lanqiao;
import org.junit.Test;
import org.lanqiao.aop.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest
{
@Test
public void testPrint()
{
ApplicationContext ctx =
new ClassPathXmlApplicationContext("aop.xml");
Hello hello = (Hello)ctx.getBean("hello");
hello.print();
}
}
5.输出结果
相互学习,共同指教!