面向切面编程,横向编程思想,区别于传统的纵向提取思想,可以用代理思想理解。
底层实现原理:动态代理。jdk动态代理(只能代理实现了接口的类)和Cglib动态代理(可代理没实现接口的类,生成子类对象)。具体选择哪种代理模式,Spring会根据是否实现接口来选择,底层自动切换。
作用:对程序进行增强。在不修改源代码的情况下,AOP可以进行权限校验、日志记录、性能监控、事务控制。
AOP思想是由AOP联盟提出的,Spring是最好的实现着,Spring自己的AOP过于繁琐,引入了Aspectj的AOP作为自己的AOP(Spring有两套AOP开发方式,基于Aspectj仍在使用->XML配置)。
AOP开发中的相关术语
JoinPoint(连接点):可以被拦截的点。(可以被增强的点)。
PointCut(切入点):真正被拦截到的点。(实际被增强的点)。
Advice(通知/增强):(对某个方法增强,增强的方法称为通知)。通知:前置通知(权限校验)/后置通知(日志记录)/环绕通知(性能监控)。
Introduction(引介):(也是一种增强,对某个类增强)。
Target:被增强的对象。
Waving(织入):将Advice 应用到 Target 的过程。织入增强后会产生代理。
Aspect(切面):多个 通知 和 多个切入点 的组合。
AOP编程入门
AOP底层基于动态代理,Spring具体使用那种代理模式根据我们定义的继承实现关系决定。Spring框架使用AOP基于XML配置的编程思路如下:
首先创建接口&实现类(或创建实体类),再applicationContext.xml中引入
创建ProductDao
package com.aloha.proxy;
public interface ProductDao {
void add();
void delete();
void change();
void find();
}
创建ProductDaoImpl
package com.aloha.proxy;
public class ProductDaoImpl implements ProductDao {
@Override
public void add() {
System.out.println("add");
}
@Override
public void delete() {
System.out.println("delete");
}
@Override
public void change() {
System.out.println("change");
}
@Override
public void find() {
System.out.println("find");
}
}
创建Aspect类以及Advice
package com.aloha.proxy;
/**
* 切面类:放的是切入点&通知的组合
*/
public class MyAspectXML {
public void checkPri(){
System.out.println("权限校验");
}
public void logging(){
System.out.println("日志记录");
}
}
引入bean对象,配置切面,切入点,前向切入
<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="productDao" class="com.aloha.proxy.ProductDaoImpl" />
<!-- 将切面类交给Spring管理 -->
<bean id="myAspect" class="com.aloha.proxy.MyAspectXML" />
<!-- 通过aop配置完成对目标类产生代理 -->
<aop:config>
<!-- aop切入点的id随便写,expression:表达式配置哪些类的那些方法需要被增强
* 任意返回值
.. 任意参数
-->
<aop:pointcut id="pointcut1" expression="execution(* com.aloha.proxy.ProductDaoImpl.add(..))" />
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1" />
</aop:aspect>
</aop:config>
</beans>
创建Spring测试类,测试:
package com.aloha.proxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringJunit {
@Resource(name="productDao")
private ProductDao productDao;
@Test
public void test(){
productDao.add();
productDao.change();
productDao.delete();
productDao.find();
}
}
测试结果:
可以看到我们在添加用户的方法前向切入一个权限校验的方法,通过Spring的aop实现增强代码量、耦合度都大大降低!
AOP通知类型
以下几类通知来自顾名思义:
前置通知:在目标方法执行之前的操作。
后置通知:在目标方法执行之后的操作。
环绕通知:在目标方法执行之前和之后的操作(事务执行)。
异常抛出通知:在程序出现异常的时候执行的操作(事务管理使用-回滚)。
最终通知:无论代码是否有异常,这里的一定会执行。
控制反转(Inversion of Control)
对象的生命周期不再由代码控制,而是交给spring管理。
BeanFactoryPostProcessor.java bean解析后实例化前的处理;
BeanDefinitionRegistryPostProcessor.java 继承了上面的接口,