一、动态代理
在学习AOP之前必须学习反射和动态代理的知识,可以参阅我的博客:
动态代理
二、AOP概念
意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强;
优势:减少重复代码,提高开发效率,并且便于维护。
常用的动态代理技术:
(1)JDK代理:基于接口的动态代理技术
(2)CGLIB代理:基于父类的动态代理技术。
在Spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理方式。
相关概念:
Target(目标对象):代理的目标对象
Proxy(代理):一个类被AOP织入增强后,就产生了一个结果代理类
JoinPoint(连接点):可以被增加的方法(不一定被增强)
PointCut(切点): 被增强的连接点
Advice(通知):描述增强逻辑的方法
Aspect(切面):是切点和通知的结合
Weaving(切入): 是指将通知应用到目标对象来创建代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类装载器织入。
三、AOP开发需要编写的内容
- 编写核心业务代码(目标类的目标方法)
- 编写切面类,切面类中有通知
- 在配置文件中,配置织入关系(将哪些通知与哪些连接点进行结合)
为了使用aop元素,必须在XML配置中声明Spring的aop命名空间:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
...
...
</beans>
四、两种开发方式
4.1 基于XML的AOP开发
- 切点表达式的写法
最常用的是第三种,表示该包下的任意类的任意方法。
- 通知的配置语法
- 切点表达式的抽取
声明一个切点,之后根据可以直接根据id调用,例如:
<!-- 声明切点-->
<aop:pointcut id="myPointcut" expression="execution(void AOP.XML.*.*(..))"/>
<aop:aspect ref="myAspect">
<!-- 切点+通知 -->
<aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturnning" pointcut="myPointcut"/>
</aop:aspect>
- 实例代码
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 目标对象 -->
<bean id="target" class="AOP.XML.Target"></bean>
<!-- 切面对象 -->
<bean id="myAspect" class="AOP.XML.MyAspect"></bean>
<!-- 配置织入:告诉spring框架,哪些方法(切点)需要进行哪些增强(前置、后置...) -->
<aop:config>
<!-- 声明切点-->
<aop:pointcut id="myPointcut" expression="execution(void AOP.XML.*.*(..))"/>
<!-- 声明切面 -->
<aop:aspect ref="myAspect">
<!-- 切点+通知 -->
<aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturnning" pointcut="myPointcut"/>
</aop:aspect>
</aop:config>
</beans>
public interface TargetInterface {
void require();
}
public class Target implements TargetInterface{
public void require() {
System.out.println("running...");
}
}
public class MyAspect {
public void before(){
System.out.println("前置增强");
}
public void afterReturnning(){
System.out.println("后置增强");
}
}
测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext.xml")
public class SpringTest {
@Autowired
private TargetInterface target;
@Test
public void test(){
target.require();
}
}
4.2 基于注解的AOP开发
1.步骤
- 使用@Aspect标注切面类
- 使用
@通知注解
标注通知方法:语法——@通知注释("切点表达式")
- 在配置文件中配置aop自动代理:
<aop:aspectj-autoproxy/>
2.注解类型同样是5种
3.实例
注:需要在xml文件中声明aop和context的命名空间。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启组件扫描 -->
<context:component-scan base-package="AOP.Annotation"/>
<!-- 启动AOP自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
@Component
@Aspect //标注为切面类
public class MyAspect {
@Before("execution(void AOP.Annotation.*.*(..))")
public void before(){
System.out.println("前置增强");
}
@AfterReturning("execution(void AOP.Annotation.*.*(..))")
public void afterReturnning(){
System.out.println("后置增强");
}
}
public interface TargetInterface {
void require();
}
@Component
public class Target implements TargetInterface {
public void require() {
System.out.println("running...");
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext-anno.xml")
public class SpringTest {
@Autowired
private TargetInterface target;
@Test
public void test(){
target.require();
}
}