AOP基于纯注解开发
程序员文章站
2022-03-01 12:57:26
...
目录
2.创建目标接口,定义抽象方法,并实现目标接口的实现类,重写方法(目标方法)
前言
使用xml配置AOP的方法,稍微有些许麻烦,在企业开发中,绝大部分使用注解开发的,效率杠杠的。如果需要了解基于xml方式配置AOP,去找的上一篇文章!
提示:以下是本篇文章正文内容,下面案例可供参考
一、纯注解开发
- 其实注解开发就是剔除掉Spring的配置文件,使用注解的方式去替代在配置文件所做的事情
- 在xml配置文件,我们需要把通知类、目标类使用<bean>标签创建出来,然后交给Spring的IOC容器管理。然后在配置AOP
二、操作步骤
1.导入依赖
代码如下(示例):
<dependencies>
<!--Spring上下文核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--AOP的实现包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--Spring和单元测试集成-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.
创建目标接口,定义抽象方法,并实现目标接口的实现类,重写方法(目标方法)
代码如下(示例):
/**
* @Author:Yan
* @Date 2022/01/21 20:07
* @Description 目标接口
**/
public interface Target {
String getName(String name);
}
/**
* @Author:Yan
* @Date 2022/01/21 20:08
* @Description 目标接口的实现类
**/
//@Component注解,相当于使用了<bean>,表示创建类的对象并交给IOC容器管理
@Component
public class TargetImpl implements Target {
@Override
public String getName(String name) {
System.out.println("目标方法...."+name);
return name;
}
}
3.创建通知类,定义通知方法
代码如下(示例):
/**
* @Author:Yan
* @Date 2022/01/21 19:56
* @Description 3、创建通知类,定义通知方法
* 1、通知类使用@Aspect表示该类为切面类 并使用@Component注解表示创建该类对象交给Spring管理
* 2、定义一个方法,使用@Pointcut("切入点表达式")注解 该方法毫无意义
* 3、方法使用@通知类型("切入点表达式的方法ming()")
**/
@Aspect //表示该方类为切面类
@Component
public class MyAdvice {
//2、定义一个方法,使用@Pointcut("切入点表达式")注解
@Pointcut("execution(* com.itheima..*.*(..))")
public void pointcut() {
}
//3、方法使用@通知类型
@Before("pointcut()")
public void before() {
System.out.println("前置通知-->打印日志");
}
@After("pointcut()")
public void after() {
System.out.println("最终通知-->打印日志");
}
@AfterReturning("pointcut()")
public void afterRun() {
System.out.println("返回后通知-->打印日志");
}
@AfterThrowing("pointcut()")
public void afterThrow() {
System.out.println("抛出异常后通知-->打印日志");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
//获取目标方法的参数
pjp.getArgs()[0] = "李四";
System.out.println("环绕通知-->打印日志");
//将设置好的目标方法参数传回去
Object proceed = pjp.proceed(pjp.getArgs());
//并返回,如果不返回,那么接收到的返回值为null
return proceed;
}
}
4.创建Spring核心配置类
/**
* @Author:Yan
* @Date 2022/01/21 20:09
* @Description 核心配置类
* 1、使用@Configuration 表示为该类为核配置类
* 2、使用@ComponentScan("包的路径") 表示为开启注解扫描
* 3、使用@EnableAspectJAutoProxy 表示开启AOP注解扫描
**/
@Configuration //表示该类为Spring核心配置类
@ComponentScan("com.itheima") //开启注解扫描
@EnableAspectJAutoProxy //表示开启AOP注解驱动
public class AppConfig {
}
5.测试类
/**
* @Author:Yan
* @Date 2022/01/21 20:14
* @Description 测试纯注解
**/
@RunWith(SpringJUnit4ClassRunner.class) //表示该类测试类
@ContextConfiguration(classes = AppConfig.class)
public class textAnno {
//定义目标类的属性 使用@Autowiredr注解为该属性注入数据
@Autowired
private Target target;
@Test
public void method() {
//调用方法
String name = target.getName("张三");
System.out.println(name);
}
}
6.测试结果
环绕通知-->打印日志
前置通知-->打印日志
目标方法....李四
最终通知-->打印日志
返回后通知-->打印日志
李四
三、注解解释:
- @Aspect:该注解作用在类上,表示该类是一个切面类。替代xml方式中的<aop:aspect ref="通知类唯一标识">
-
@Component:该注解作用在类上,用于创建该类的对象并交给IOC容器管理,替代xml方式中的<bean>标签
-
@Pointcut("execution= "):该注解作用于方法上,使用当前方法名作为切入点引用名称,方法毫无意义。execution属性用于定义切入点表达式。替代xml方式中的<aop:pointcut id="" expression="execution(切入点表达式)"/>
-
@Before("切入点方法名()") 、@After("切入点方法名()")、@AfterReturning("切入点方法名()")、@AfterThrowing("切入点方法名()")、@Around("切入点方法名()"):这些注解作用于方法上,表示该方法属于何种通知类型,并指定切入点表达式。
-
@Configuration 该注解作用于类上,表示该类为Spring核心配置类 一般用于配置类上
-
@ComponentScan("com.itheima") 该注解作用于类上,表示开启Spring注解扫描。 一般用于配置类上
-
@EnableAspectJAutoProxy 该注解作用于类上,表示开启AOP注解驱动。一般用于配置类上
-
@RunWith(SpringJUnit4ClassRunner.class) 该注解作用于类上,表示该类测试类。
-
@ContextConfiguration(classes = AppConfig.class) 该注解作用于类上,用于读取Spring配置文件。替代了xml方式需要创建工厂对象
四、注意事项:
-
如果一个类中的方法被使用AOP增强了 则在SpringIOC容器中管理的是这个类的代理对象 代理对象类型不是实现类类型 但是属于接口类型所以 在使用 AOP之后 获取一个bean对象 通过接口类型获取 不能在通过实现类类型获取了只要类中有一个方法被AOP增强了 则存在Spring IOC容器中的bean对象 就是代理对象 必须使用接口类型获取接收
-
定义环绕增强时 就需要设置方法参数了,如果不设置 其功能就等价于前置增强 ProceedingJoinPoint就是要进行增强的目标方法
不是设置参数时,会执行环绕通知,而不会执行前置通知
使用 ProceedingJoinPoint获取方法参数 重新赋值 修改参数 需要将该参数传递给目标方法
proceed():调用目标方法执行 如果有参数就在小括号中传递
环绕通知可以使用 ProceedingJoinPoint修改目标方法的返回值,那么该环绕通知的方法需要有返回值
上一篇: 深度学习--自动微分
下一篇: 桶列表(寒假每日一题 32)