AOP编程通过@AspectJ注解的方式
运行环境 Eclipse
AOP 面向切面编程,Spring是支持AOP切面编程的框架之一,其实现的方式是方法拦截。
面向切面编程:通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能。
举个例子:当我们平常正常执行SQL语句的步骤为
但是如果我们使用AOP技术编程的话,我们主要关注到的点就是执行SQL那一步,其他的都已经被AOP实现了,我们主要关注的只有业务逻辑的实现而已。
面向切面编程的一些术语
- 切面 Aspect:切面就是一个环境,一个工作的环境,比如上面的那个图中数据库事务就是一个切面。
- 通知 Adice:切面开启后切面的方法,有五种:
前置通知 before:动态代理反射原有对象方法或执行环绕通知前执行。
后置通知 after:动态代理反射原有对象方法或执行环绕通知后执行。
返回通知 afterReturning:动态代理反射原有对象方法或执行环绕通知后执行。
异常通知 afterThrowing:动态代理反射原有对象方法或执行环绕通知产生异常执行。
环绕通知 aroundThrowing:在动态代理,可以取代当前被拦截对象的方法,通过参数或反射调用拦截对象的方法。 - 引入 Introduction:允许在现有的类里添加自定义的类和方法。
- 切点 Pointcut:被拦截的方法就是一个切点。
- 连接点 join point:就是一个判断条件用来指定哪些是切点。
- 织入 Weaving:生成代理对象的过程。切面将切点和被拦截的方法按照一定的逻辑织入到约定流程中。
@AspectJ注解使用的实例
首先使用AOP编程不仅仅需要Spring框架所需的依赖jar包,AOP编程也是需要jar包的。
eclipse官网就有下载下面的两个jar包
aspectjrt.jar
aspectjweaver.jar
还有一个 aopalliance.jar 找到的可以下载的位置:下载地址
项目结构如下
PS:POJO的Role类是只有三个参数long id,String roleName,String note加上对应的get/set方法以及有参无参构造器即可。
第一步:选择切点
接口的定义(之所以需要使用接口,是因为在这里使用的JDK的动态代理方式,如果使用的是CGLIB动态代理是不需要接口的)
public interface RoleService {
public void printRole(Role role);
}
提供这个接口的实现类
@Component 来自org.springframework.stereotype.Component
这个注解的作用是装配Bena但是这个注解还需要同时定义一个Java Config类。
@Component
public class RoleServiceImpl implements RoleService{
@Override
public void printRole(Role role) {
System.out.println("{ id = " + role.getId()
+ ",roleName = " + role.getRoleName()
+ ",note = " + role.getNote() +"}");
}
}
第二步:切面
定义切面 使用注解的方式
execution表达式中出现*号是需要后接一个空格的,注意,我被坑的很惨这个位置…
引入@Pointcut注解使用execution表达式可以在后续的通知方法的注解中复用,而不需要多次输入execution表达式变得麻烦。
其中execution表达式就是一个连接点,Spring通过这个正则表达式判断是否需要拦截你的方法,具体的其他的AspectJ的指示器可以查询AspectJ框架的资料。
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class RoleAspect {
//execution定义的正则式 Spring通过这个正则表达式判断是否需要拦截你的方法
//注意 *号后面需要跟一个空格
@Pointcut("execution(* com.ww.ssm.aop.service.impl.RoleServiceImpl.printRole(..))")
public void function() {}
@Before("function()")
public void before() {
System.out.println("before...");
}
@After("function()")
public void after() {
System.out.println("after...");
}
@AfterReturning("function()")
public void afterReturning() {
System.out.println("afterReturning...");
}
@AfterThrowing("function()")
public void afterThrowing() {
System.out.println("afterThrowing...");
}
@Around("function()")
public void around(ProceedingJoinPoint jp) {
System.out.println("around before....");
try {
jp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around after....");
}
}
第三步:测试AOP
配置Spring Bean
@EnableAspectJAutoProxy注解表达使用AspectJ框架的自动代理,之后Spring才会生成动态代理对象,从而可以使用AOP,之后通过getRoleAspect()方法生成一个切面实例。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.ww.ssm.aop")
public class AopConfig {
@Bean
public RoleAspect getRoleAspect() {
return new RoleAspect();
}
}
测试代码
public class Test {
public static void main(String[] args) {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AopConfig.class);
RoleService roleService = (RoleService) ctx.getBean(RoleService.class);
Role role = new Role();
role.setId(2L);
role.setRoleName("role name");
role.setNote("note");
roleService.printRole(role);
System.out.println("----------测试异常通知------------");
//触发空指针异常
role = null;
roleService.printRole(role);
}
}
结果
完成!!!