AspectJ 是一个基于 Java 语言的 AOP 框架,它扩展了 Java 语言。Spring 2.0 以后,新增了对 AspectJ 方式的支持,新版本的 Spring 框架,建议使用 AspectJ 方式开发 AOP。
使用 AspectJ 开发 AOP 通常有两种方式: - 基于 XML 的声明式。 - 基于 Annotation 的声明式。
本教程主要以注解开发方式进行讲解。
AspectJ Annotation 常用注解如下表:
| 名称 | 说明 |
|---|---|
| @Aspect | 用于定义一个切面。 |
| @Pointcut | 用于定义一个切入点。 |
| @Before | 用于定义前置通知,相当于 BeforeAdvice。 |
| @AfterReturning | 用于定义后置通知,相当于 AfterReturningAdvice。 |
| @Around | 用于定义环绕通知,相当于MethodInterceptor。 |
| @AfterThrowing | 用于定义抛出通知,相当于ThrowAdvice。 |
| @After | 用于定义最终final通知,不管是否异常,该通知都会执行。 |
| @DeclareParents | 用于定义引介通知,相当于IntroductionInterceptor(不要求掌握)。 |
实例:
项目结构图如下:
实现步骤
1.在pom.xml添加aop和aspectJ依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.simoniu</groupId>
<artifactId>springbase</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<spring.version>5.2.5.RELEASE</spring.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
2.编写学生实体类
package com.entity;
public class Students {
private String sid; //学号
private String sname; //姓名
private String gender; //性别
private String major; //专业
public Students() {
}
public Students(String sid, String sname, String gender, String major) {
this.sid = sid;
this.sname = sname;
this.gender = gender;
this.major = major;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
@Override
public String toString() {
return "Students{" +
"sid='" + sid + '\'' +
", sname='" + sname + '\'' +
", gender='" + gender + '\'' +
", major='" + major + '\'' +
'}';
}
}
3.定义业务逻辑接口
package com.dao;
public interface BusinessDao<T> {
public void add(T obj);
public void query(String identify);
public void delete(String identify);
public void update(T obj);
}
4.定义学生业务逻辑接口
package com.dao;
public interface StudentsDao<Students> extends BusinessDao<Students> {
}
5.编写学生业务逻辑实现类
package com.dao.impl;
import com.dao.StudentsDao;
import org.springframework.stereotype.Repository;
@Repository
public class StudentsDaoImpl implements StudentsDao<Students> {
public void add(Students s) {
System.out.println("新增学生:"+s);
}
public void query(String identify) {
System.out.println("查询学生编号:" + identify);
}
public void delete(String identify) {
System.out.println("删除学生编号:" + identify);
}
public void update(Students s) {
System.out.println("修改学生:"+s);
}
}
6.在SpringConfiguration配置类中配置一个Students类型的bean
package com.config;
import com.entity.Students;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfiguration {
@Bean("s1")
public Students getStudents1(){
return new Students("S001","张三","男","软件工程");
}
}
7.定义业务逻辑切面类
package com.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component//类注解
@Aspect
public class BusinessAspect {
//声明公共切入点
@Pointcut("execution(* com.dao.impl.StudentsDaoImpl.*(..))")
public void myPointcut() {
}
@Before(value = "myPointcut()")
public void checkPri() {
System.out.println("权限的校验...");
}
@AfterReturning(value="myPointcut()")
public void logger() {
System.out.println("日志记录...");
}
@AfterThrowing(value="myPointcut()",throwing="e")
public void afterThrowing(Throwable e) {
System.out.println("异常抛出通知..."+e.getMessage());
}
@After(value="myPointcut()")
public void after() {
System.out.println("最终通知...");
}
//环绕通知;
@Around(value="myPointcut()")
public Object around(ProceedingJoinPoint joinPoint) {
Object obj=null;
try {
System.out.println("环绕内的前置通知");
obj = joinPoint.proceed();
System.out.println("环绕内的后置通知");
} catch (Throwable e) {
System.out.println("环绕内的异常抛出通知");
e.printStackTrace();
} finally {
System.out.println("环绕内的最终通知");
}
return obj;
}
}
8.在applicationContext.xml中开启aspectJ注解
由于Spring默认不支持AspectJ注解方式,必须在配置文档中开启AspectJ注解。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解类 -->
<context:component-scan base-package="com"/>
<!-- 确定AspectJ注解生效 -->
<aop:aspectj-autoproxy/>
</beans>
9.编写测试类
package com.test;
import com.dao.StudentsDao;
import com.entity.Students;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringAspectDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Students s = (Students) context.getBean("s1");
StudentsDao studentsDaoImpl = (StudentsDao) context.getBean("studentsDaoImpl");
System.out.println(s);
studentsDaoImpl.add(s);
}
}
运行结果:
Students{sid='S001', sname='张三', gender='男', major='软件工程'}
环绕内的前置通知
权限的校验...
新增学生:Students{sid='S001', sname='张三', gender='男', major='软件工程'}
环绕内的后置通知
环绕内的最终通知
最终通知...
日志记录...
基于注解方式实现以上案例,我们无需配置applicationContext.xml,只需要把SpringConfiguration 配置类改写为如下:
package com.config;
import com.entity.Students;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com")
@EnableAspectJAutoProxy //表示启用aspectJ
public class SpringConfiguration {
@Bean("s1")
public Students getStudents1(){
return new Students("S001","张三","男","软件工程");
}
}