一、AOP简介
1.什么是AOP
AOP是Aspect Oriented Programming的缩写,是面向切面编程的意思,
是通过预编译方式和运行期动态代理实现程序功能统一维护的一种方式。
动态代理:在不修改目标方法代码的基础上对目标方法的功能进行增强,可以实现程序功能的松耦合。
2.AOP的作用
和动态代理一样,在程序运行期间,可以在不修改源码的情况下对方法的功能进行增强
只是使用AOP就不用自己去手写动态代理,Spring已经帮我们封装好了,
我们只需要去配置就可以使用,实现功能和增强和松耦合。
使用AOP可以对各个业务逻辑部分进行隔离,也就是解耦。
3.AOP的底层实现
在运行期间,Spring通过动态代理技术动态地生成代理对象,代理对象的方法执行时,
进行增强功能的介入、调用目标功能的方法,从而实现功能的增强。
4.AOP的动态代理技术
AOP常用的动态代理技术有两种:
- JDK代理:基于接口的动态代理技术
- cglib代理:基于父类的动态代理技术
5.AOP相关的术语
- Target(目标):要代理的对象
- Proxy(代理):一个类被AOP植入增强后,就产生了一个结果代理类
- Jointpoint(连接点):可以被拦截的点,即可以被增强的方法
- Pointcut(切点):最后真正被增强的连接点称为切点
- Advice(增强):要对目标方法进行增强的方法
- Aspect(切面):目标方法和增强结合称为切面
- Weaving(织入):把增强和目标方法进行结合的过程叫做织入
二、AOP的基本开发步骤
- 编写核心业务代码,即目标类的目标方法
- 编写切面类,切面类中有增强方法
- 在配置文件中配置织入关系,即指定哪些切点与哪些增强相结合
AOP技术实现的内容:首先我们要在配置文件中配置切点,即指定哪些目标方法需要被增强,
然后Spring就会监听切点(需要被增强的目标方法)的执行,当切点一旦被执行了,Spring就会去创建该切点
属于的目标对象(target)的目标代理(proxy),根据增强的类别,在代理对象(proxy)对应的位置将增强功能织入。
三、基于xml的AOP开发
1.导入AOP的相关坐标
需要导入spring-context、aspectjweaver还有进行单元测试需要的spring-test坐标
2.创建目标接口和目标类(内部有切点)
public interface TargetInterface {
public void service();
}
public class Target implements TargetInterface {
@Override
public void service() {
System.out.println("Target(目标)对象提供了服务........");
}
}
3.创建切面类(内部有增强方法)
public class MyAspect {
public void beforeEnhance(){
System.out.println("前置增强执行.......");
}
public void afterReturningEnhance(){
System.out.println("后置增强执行.......");
}
}
4.在applicationContext.xml中注册目标类和切面类
<!--目标对象-->
<bean id="target" class="com.lxl.aop.Target"/>
<!--切面对象-->
<bean id="myAspect" class="com.lxl.aop.MyAspect"/>
5.在applicationContext.xml中配置织入关系
首先要引入aop的命名空间,和之前引入context命名空间的方法一样,复制粘贴再修改就可以了
关于切点表达式的写法,可以参考我的另外一篇文章:Spring学习之AOP的切点表达式详解
(如果链接失效了,可以直接在我的SSM框架专栏找,就在这篇文章附近)
applicationContext.xml的全部代码:
<!--配置织入关系:告诉Spring,哪些切点(目标方法)需要进行哪些增强(前置、后置等等...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=增强+切点-->
<aop:before method="beforeEnhance" pointcut="execution(public void com.lxl.aop.Target.service())"/>
<aop:after method="afterReturningEnhance" pointcut="execution(public void com.lxl.aop.Target.service())"/>
</aop:aspect>
</aop:config>
6.编写测试代码进行测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Autowired
private TargetInterface target;
@Test
public void test(){
// 不再像之前动态代理的代码一样去调用proxy,直接调target,Spring会帮我们自动实现代理
target.service();
}
}
四、基于注解的AOP开发
导包、创建目标接口和目标类、创建切面的方法和刚才xml配置是完全一样的,注解配置的区别在于:
4.在切面类中使用注解配置织入关系
首先,在Target类和MyAspect类上加上@Component注解,把对象的创建权交给Spring容器
然后才进入最关键的一步:在切面类中配置织入关系
@Component("myAspect")
@Aspect // 告知Spring容器当前MyAspect类是一个切面类
public class MyAspect {
@Pointcut("execution(* com.lxl.aopAnnotation.Target.*(..))")
public void myPoint(){}
@Before("MyAspect.myPoint()")
public void beforeEnhance(){
System.out.println("前置增强,在切点的前面执行.......");
}
@AfterReturning("myPoint()")
public void afterReturningEnhance(){
System.out.println("后置增强,在切点执行后执行.......");
}
@Around("myPoint()")
public Object aroundEnhance(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强,在切点之前会执行......");
// Proceeding JoinPoint:切点
Object proceed = pjp.proceed();
System.out.println("环绕后增强,在切点之后会执行......");
return proceed;
}
@After("myPoint()")
public void afterEnhance(){
System.out.println("最终增强,无论切点是否执行,最终增强都会执行......");
}
@AfterThrowing("myPoint()")
public void throwingEnhance(){
System.out.println("异常抛出增强,只有在切点抛出异常的时候才会执行......");
}
}
5.在applicationContext-anno.xml中开启组件扫描和AOP的自动代理
我也不知道为啥黑马的教学视频这么。。,命名都使用注解配置了,最后还去用一个applicationContext-anno.xml
加上组件扫描和AOP自动代理的方式来加载配置,直接写一个配置类SpringConfiguration不就得了。。。
<?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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置组件扫描-->
<context:component-scan base-package="com.lxl.aopAnnotation"/>
<!--配置AOP的自动代理-->
<aop:aspectj-autoproxy/>
</beans>