版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lizhengwei1989/article/details/88599976
技术分析之AOP的相关术语
1. Joinpoint(连接点) -- 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
2. Pointcut(切入点) -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
3. Advice(通知/增强) -- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
4. Introduction(引介) -- 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
5. Target(目标对象) -- 代理的目标对象
6. Weaving(织入) -- 是指把增强应用到目标对象来创建新的代理对象的过程
7. Proxy(代理) -- 一个类被AOP织入增强后,就产生一个结果代理类
8. Aspect(切面) -- 是切入点和通知的结合,以后咱们自己来编写和配置的
public class UserDaoImpl{
public void save()
public void update()
}
1. Joinpoint(连接点) -- 所有的方法:save、update
2. Pointcut(切入点) -- 要增强的方法,例如要在save的时候增加保存日志的增强,那么save就是切入点
3. Advice(通知/增强) -- 具体的增强,例如保存日志
5. Target(目标对象) -- UserDaoImpl
6. Weaving(织入) -- 把增强(保存日志)添加到目标,生成代理的过程
7. Proxy(代理) -- 生成的代理对象
8. Aspect(切面) -- 切入点和通知 组合成切面:通知需要自己写,切入点需要配置
技术分析之AspectJ的XML方式完成AOP的开发
1. 创建Spring的配置文件,引入具体的AOP的schema约束
<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">
2. 创建包结构,编写具体的接口和实现类
* com.demo2
* CustomerDao -- 接口
* CustomerDaoImpl -- 实现类
3. 将目标类配置到Spring中
<bean id="customerDao" class="com.demo2.CustomerDaoImpl"/>
4. 定义切面类
public class MyAspectXml {
// 定义通知
public void log(){
System.out.println("记录日志...");
}
}
5. 在配置文件中定义切面类
<bean id="myAspectXml" class="com.itheima.demo3.MyAspectXml"/>
6. 在配置文件中完成aop的配置
<aop:config>
<!-- 配置切面类:切入点 + 通知(类型) -->
<aop:aspect ref="myAspectXml">
<!-- 配置的前置通知,save方法执行之前,增强的方法会执行 -->
<aop:before method="log" pointcut="execution(public * com.demo3.CustomerDaoImpl.save(..))"/>
</aop:aspect>
</aop:config>
7. 完成测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo3 {
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void run1(){
customerDao.save();
customerDao.update();
customerDao.delete();
}
}
----------
切入点的表达式
1. 再配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..)),具体展开如下:
* 切入点表达式的格式如下:
* execution([修饰符] 返回值类型 包名.类名.方法名(参数))
* 修饰符可以省略不写,不是必须要出现的。
* 返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。
* 包名例如:com.demo3.BookDaoImpl
* 首先com是不能省略不写的,但是可以使用 * 代替
* 中间的包名可以使用 * 号代替
* 如果想省略中间的包名可以使用 ..
* *..*表示所有的包
* 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl表示以DaoImpl结尾的
* 方法也可以使用 * 号代替,也可以是save*,表示以save开头的
* 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..
<!--完全匹配的方式-->
<!-- <aop:before method="log" pointcut="execution(public void com.demo3.CustomerDaoImpl.save())"/> -->
<!-- public 可以省略不写 -->
<!-- <aop:before method="log" pointcut="execution(void com.demo3.CustomerDaoImpl.save())"/> -->
<!-- void,返回值可以出现 * 表示任意的返回值,返回值类型不能不写 -->
<!-- <aop:before method="log" pointcut="execution(* com.demo3.CustomerDaoImpl.save())"/> -->
<!-- 包名可以使用 * 代替,不能不写 -->
<!-- <aop:before method="log" pointcut="execution(* com.*.CustomerDaoImpl.save())"/> -->
<!-- 包的简写的方式,任意的包的结构 -->
<!-- <aop:before method="log" pointcut="execution(* *..*.CustomerDaoImpl.save())"/> -->
<!-- 编写类的写法 -->
<!-- <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save())"/> -->
<!-- 方法编写 -->
<!-- <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save*())"/> -->
execution(* *..*.*DaoImpl.save*(..)) 这个表示:返回值任意,所有包下,以DaoImpl结尾的类中的save开头的,参数为任意 的方法
AOP的通知类型
1. 前置通知
* 在目标类的方法执行之前执行。
* 配置文件信息:参考上面
* 应用:可以对方法的参数来做校验
2. 最终通知
* 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
* 在配置文件中编写具体的配置:
* <aop:after method="after" pointcut="execution(public void com.demo3.CustomerDaoImpl.save())"/>
* 应用:例如像释放资源
3. 后置通知
* 方法正常执行后的通知。
* 在配置文件中编写具体的配置:
* <aop:after-returning method="afterReturn" pointcut="execution(public void com.demo3.CustomerDaoImpl.save())"/>
* 应用:可以修改方法的返回值
4. 异常抛出通知
* 在抛出异常后通知
* 在配置文件中编写具体的配置:<aop:after-throwing method="afterThorwing" pointcut-ref="myPointcut3"/>
* 应用:包装异常的信息
5. 环绕通知
* 方法的执行前后执行。
* 在配置文件中编写具体的配置
* <aop:around method="around" pointcut="execution(public void com.demo3.CustomerDaoImpl.save())"/>
public void around(ProceedingJoinPoint joinPoint){
System.out.println("环绕通知1...");
try {
// 手动让目标对象的方法去执行
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知2...");
}
* 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
技术分析之:Spring框架的AOP技术(注解方式)导入的包和配置文件方式相同
1. 创建Spring的配置文件,引入具体的AOP的schema约束
<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">
</beans>
2. 创建包结构,编写具体的接口和实现类
* com.demo1
* CustomerDao -- 接口
* CustomerDaoImpl -- 实现类
3. 将目标类配置到Spring中
<bean id="customerDao" class="com.demo1.CustomerDaoImpl"/>
4. 定义切面类
* 添加切面和通知的注解
* @Aspect -- 定义切面类的注解
* 通知类型(注解的参数是切入点的表达式)
* @Before -- 前置通知
* @AfterReturing -- 后置通知
* @Around -- 环绕通知
* @After -- 最终通知
* @AfterThrowing -- 异常抛出通知
* 具体的代码如下
@Aspect
public class MyAspectAnno {
@Before(value="execution(public void com.demo1.CustomerDaoImpl.save())")
public void log(){
System.out.println("记录日志...");
}
}
5. 步骤六:在配置文件中定义切面类
<bean id="myAspectAnno" class="com.itheima.demo1.MyAspectAnno"/>
6. 步骤七:在配置文件中开启自动代理
<aop:aspectj-autoproxy/>
7. 完成测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
@Resource(name="customerDao")
private CustomerDao customerDao;
@Test
public void run1(){
customerDao.save();
customerDao.update();
}
}
技术分析之通知类型
1. 通知类型
* @Before -- 前置通知
* @AfterReturing -- 后置通知
* @Around -- 环绕通知(目标对象方法默认不执行的,需要手动执行)
* @After -- 最终通知
* @AfterThrowing -- 异常抛出通知
2. 配置通用的切入点
* 使用@Pointcut定义通用的切入点
@Aspect
public class MyAspectAnno {
@Before(value="MyAspectAnno.fn()")
public void log(){
System.out.println("记录日志...");
}
@Pointcut(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
public void fn(){}
}
3.before,after,around执行顺序是:around,before,after