对AOP 术语进行解释
1.连接点 类里面哪些方法可以被增强,这些方法称为连接点【如下面Student 类中的study review note 方法都可以被增强,所以都可以称为连接点】
public class Student {
public void study(){
System.out.println("海康学习aop。。。");
}
public void review(){
System.out.println("海康aop。。。");
}
public void note(){
System.out.println("做aop笔记。。。");
}
}
2.切入点 实际被真实增强的方法,称为切入点【表示要增强那个方法,例如:增强study 方法,那么study 就是切入点】
3.通知(增强) (1)实际增强的逻辑部分称为通知(增强) (2)通知多种类型:
- 前置通知:就是在增强该方法前执行:使用
@Before 注解 - 后置通知:就是在增强该方法后执行:使用
@AfterReturning 注解,如果出现异常则不会该增强方法 - 环绕通知:就是在该方法前后都会执行:
@Around 注解,需要传入ProceedingJoinPoint 类调用proceed()方法表示调用需要增强的方法 - 异常通知:就是该方法出现异常才会执行:
@AfterThrowing 注解 - 最终通知:就是该方法不管是否出现异常都会执行【相当于
try 中的finally 】@After 注解
4.切面 把通知的行为应用到切入点过程中
例如:对`study`方法进行增强,
在`study`执行前先执行`paly方法`,
这一过程就可以理解为切面
AOP 实现准备工作
1.Spring 框架一般都是基于AspectJ 实现AOP 操作
? AspectJ 不是Spring 组成部分,独立AOP 框架,一般把AspectJ 和Spring 框架一起使用,进行AOP 操作
2.基于AspectJ 实现AOP 操作有两种方式:
-
基于xml 配置文件方式 -
基于注解方式实现方式(推荐) -
使用AspectJ 实现AOP 操作第一步引入 jar 包
4.切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:execution([权限修饰符][返回类型][类全路径][方法名](参数列表))
返回类型可以不写
举例1:
对com.haikang.dao.UserDao类里面的`add`方法进行增强
execution(* com.haikang.dao.UserDao.add(..))
举例2:
对com.haikang.dao.UserDao类里面所有方法进行增强
execution(* com.haikang.dao.UserDao.*(..) )
举例3:
对com.haikang.dao包里面所有有类,类里面所有方法进行增强
execution(* com.haikang.*.*(..))
AOP 操作AspectJ
1.创建类,在类里面定义方法 2.创建增强类(编写增强逻辑代码)【需要在该类中 @Aspect 表示是增强类】 3.进行通知的配置 1.在Spring 配置文件中,需要开启两个命名空间context 和aop 2.开启注解扫描 3.使用注解注入被增强类和增强类的对象 4.在增强类上面添加@Aspect 【表示该类为代理类】 5.Spring 配置文件中开启生成代理对象 4.配置不同类型通知 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
步骤
1.创建类,在类里面定义方法,并且在IOC 容器中注入该类对象
@Component
public class Student {
public void study(){
System.out.println("海康学习aop。。。");
}
public void review(){
System.out.println("海康aop。。。");
}
public void note(){
System.out.println("做aop笔记。。。");
}
}
2.定义增强类,并且添加@Aspect 注解表示是代理类,同时并在IOC 容器中注入该类对象
@Component
@Aspect
public class StudentProxy {
@Before("execution(* com.haikang.aop.jdk2.Student.study(..))")
public void before(){
System.out.println("执行前增强...");
System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
}
}
3.创建bean.xml 文件,引入context 命名空间和aop 命名空间,在配置文件中开启组件扫描和开启自动生成代理对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.haikang.aop.jdk2"/>
<aop:aspectj-autoproxy />
</beans>
test 类
public class AopTest {
@Test
public void testAop(){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Student student = context.getBean("student", Student.class);
student.study();
}
}
前置增强 表示是在执行被增强的方法执行,不管被增强的方法是否出现异常,都会执行
@Before("execution(* com.haikang.aop.jdk2.Student.study(..))")
public void before(){
System.out.println("执行前增强...");
System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
}
环绕增强:
public void review(){
System.out.println("海康复习aop两分钟。。。呵呵,够了");
}
@Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("在复习`aop前打三个小时王者荣耀......`");
joinPoint.proceed();
System.out.println("复习完`aop`刷五个小抖音......");
}
注意是:环绕增强,被增强的方法如果出现了异常,只会执行前的增强,没有对被方法执行后进行增强 例如:手动模拟一个算数异常
@Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("在复习`aop前打三个小时王者荣耀......`");
joinPoint.proceed();
System.out.println("复习完`aop`刷五个小抖音......");
}
public void review(){
int i = 10/0;
System.out.println("海康复习aop两分钟。。。呵呵,够了");
}
后置增强 特点是:后置通知,当被增强的程序出现异常时,则该增强方法则不会被执行
public void note(){
System.out.println("海康做aop笔记是认真的。。。");
}
@AfterReturning("execution(* com.haikang.aop.jdk2.Student.note(..))")
public void afterReturning(){
System.out.println("对做笔记方法进行后置增强,做笔记我是认真的,哈哈。。。");
}
异常通知:表示只有被增强的方法出现异常时,才会执行该增强方法
public void study(){
int[] arr = {1,2};
arr[5] = 10;
System.out.println("海康学习aop。。。");
}
@AfterThrowing("execution(* com.haikang.aop.jdk2.Student.study(..))")
public void throwing(){
System.out.println("被增强的方法出现异常了。。。呵呵");
}
最终异常:【不管是否出现异常都会执行方法】
public void finallyMethod(){
System.out.println("学习。。。");
}
@After("execution(* com.haikang.aop.jdk2.Student.finallyMethod(..))")
public void after(){
System.out.println("最终还是要好好学习的,不管是否出现异常。。。");
}
综合案例
1.定义被增强类
@Component
public class Student {
public void study(){
int[] arr = {1,2};
arr[5] = 10;
System.out.println("海康学习aop。。。");
}
public void review(){
int i = 10/0;
System.out.println("海康复习aop两分钟。。。呵呵,够了");
}
public void note(){
System.out.println("海康做aop笔记是认真的。。。");
}
public void finallyMethod(){
System.out.println("学习。。。");
}
}
2.定义增强类
@Component
@Aspect
public class StudentProxy {
public void before(){
System.out.println("执行前增强...");
System.out.println("表示在执行Study方法先打一小王者荣耀,三个小时");
}
@Around("execution(* com.haikang.aop.jdk2.Student.review(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("在复习`aop前打三个小时王者荣耀......`");
joinPoint.proceed();
System.out.println("复习完`aop`刷五个小抖音......");
}
@AfterReturning("execution(* com.haikang.aop.jdk2.Student.note(..))")
public void afterReturning(){
System.out.println("对做笔记方法进行后置增强,做笔记我是认真的,哈哈。。。");
}
@AfterThrowing("execution(* com.haikang.aop.jdk2.Student.study(..))")
public void throwing(){
System.out.println("被增强的方法出现异常了。。。呵呵");
}
@After("execution(* com.haikang.aop.jdk2.Student.finallyMethod(..))")
public void after(){
System.out.println("最终还是要好好学习的,不管是否出现异常。。。");
}
}
3.定义xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.haikang.aop.jdk2"/>
<!--开启生成代理类-->
<aop:aspectj-autoproxy />
</beans>
4.test类
public class AopTest {
@Test
public void testAop(){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
Student student = context.getBean("student", Student.class);
student.finallyMethod();
}
}
细节1:相同的切入点抽取
就是在对同一个切入点进行增强,可以将相同的切入点进行抽取
使用的@Pointcut 注解
@Pointcut(value = "execution(* com.haikang.aopAnno.User.add(..))")
@Component
@Aspect
public class UserProxy {
@Pointcut(value = "execution(* com.haikang.aopAnno.User.add(..))")
public void pointcutDemo(){
}
@Before("pointcutDemo()")
public void before(){
System.out.println("before执行前方法前进行增强。。。");
}
@Before("pointcutDemo()")
public void afterReturning(){
System.out.println("执行方法后进行增强");
}
@Before("pointcutDemo()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("表示对add方法执行前进行增强");
joinPoint.proceed();
System.out.println("表示对add方法执行后进行增强");
}
@Before("pointcutDemo()")
public void after(){
System.out.println("表示对add方法进行最终增强,不管是否出现异常都会执行");
}
@AfterThrowing("execution(* com.haikang.aopAnno.User.add())")
public void afterThrowing(){
System.out.println("add方法出现异常了。。。");
}
}
细节2:有多个增强类对同一个方法进行增强,设置增强优先级[重点]
在增强类上面添加注解@Order(数字类型值) ,数字类型值越小优先级越高
就是在多个类对一个类中的一个方法都进行增强时,可以设置优先级
@Component
@Aspect
@Order(1)
public class PersonProxy {
@Before("execution(* com.haikang.aopAnno.User.add(..))")
public void before(){
System.out.println("personProxy before执行前方法前进行增强。。。");
}
}
@Component
@Aspect
@Order(2)
public class UserProxy {
@Before("execution(* com.haikang.aopAnno.User.add(..))")
public void before(){
System.out.println("before执行前方法前进行增强。。。");
}
}
表示PersonProxy 增强的优先级高于UserProxy ,所以PersonProxy 增强方法先执行
细节3:完全使用注解开发
创建配置类,不需要创建xml 配置文件
注意是:需要添加@EnableAdpectJAutoProxy(proxyTargetClass = true) 注解,表示该类是一个aop 代理类,就是Spring 配置文件中开启生成代理对象作用
@Configuration
@ComponentScan(basePackages = "com.haikang.aopAnno")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigProxy {
}
test 类
@Test
public void proxyAnno(){
ApplicationContext context =
new AnnotationConfigApplicationContext(ConfigProxy.class);
User user = context.getBean("user", User.class);
user.add();
}
|