先看看 结构 吧:
- Test.java 用来测试功能
- com.test.aop 里面写了4个通知类
- com.test.dao 和 com.test.service 里面是接口
- com.test.dao.impl 和 con.test.service.impl 是接口的实现类
先写4个通知类:
前置通知:实现 MethodBeforeAdvice
后置通知:实现 AfterReturningAdvice
异常通知:实现 ThrowsAdvice
环绕通知:实现 MethodInterceptor
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class LogBefore implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object obj) throws Throwable {
System.out.println("前置通知!!!");
}
}
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class LogAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知:1.目标对象:"+target+"\n2.参数个数:"+args.length+"\n3.方法名:"+method.getName()+"\n4.返回值:"+returnValue);
}
}
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
public class LogException implements ThrowsAdvice{
public void afterThrowing(Method method, Object[] args ,Object target, NullPointerException ex) {//只捕获NullPointerException类型的异常
System.out.println("00000000000异常通知:目标对象:"+target+",方法名:"+method.getName()+",方法的参数个数:"+args.length+",异常类型:"+ex.getMessage());
}
}
public class logAround implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
try {
//proceed之前 前置通知
System.out.println("环绕通知 - 前置通知");
Object result = invocation.proceed();
//proceed之后 后置通知
System.out.println("环绕通知 - 后置通知");
}catch(NullPointerException e) {
System.out.println("环绕通知 - 空指针异常"+invocation.getThis().toString());
}
catch(Exception e) {
//异常通知
System.out.println("环绕通知 - 异常通知");
}
return null;
}
}
然后再写dao和service类
public interface StudentDao {
public void addStudent(Student student);
}
public interface StudentService {
public void addStudent(Student student);
public void deleteStudentById(int id);
public void updateStudent(Student student);
}
public class StudentDaoImpl implements StudentDao{
@Override
public void addStudent(Student student) {
System.out.println("增加学生");
}
}
package com.test.service.impl;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.test.dao.impl.StudentDaoImpl;
import com.test.entity.Student;
import com.test.service.StudentService;
public class StudentServiceImpl implements StudentService{
StudentDaoImpl studentDao;
public StudentServiceImpl() {
}
public StudentServiceImpl(StudentDaoImpl studentDao) {
super();
this.studentDao = studentDao;
}
public void setStudentDao(StudentDaoImpl studentDao) {
this.studentDao = studentDao;
}
//可以增删改,传播行为...
@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
@Override
public void addStudent(Student student) {
//studentDao = null;
studentDao.addStudent(student);
}
public void deleteStudentById(int id) {
System.out.println("模拟删除...");
}
public void updateStudent(Student student) {
System.out.println("更新学生信息...");
}
}
配置:
把StudentDaoImpl与StudentServiceImpl配置到容器中:
<bean id="studentDao" class="com.test.dao.impl.StudentDaoImpl"> </bean>
<bean id="studentService" class="com.test.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
把通知配置到容器中
<!-- 前置通知类 -->
<bean id="logBefore" class="com.test.aop.LogBefore"></bean>
<!-- 后置通知类 -->
<bean id="logAfter" class="com.test.aop.LogAfter"></bean>
<!-- 异常通知类 -->
<bean id="logException" class="com.test.aop.LogException"></bean>
<bean id="logAround" class="com.test.aop.logAround"></bean>
将方法与通知关联:
expression里面写execution表达式,多个方法则用or隔开
<aop:config>
<!-- 配置切入点(在哪里执行通知) -->
<aop:pointcut expression="execution(public void com.test.service.impl.StudentServiceImpl.addStudent(com.test.entity.Student)) or execution(public void com.test.service.impl.StudentServiceImpl.deleteStudentById(int))" id="pointcut1"/>
<!-- 连接切入点与切面 -->
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut1"/>
</aop:config>
<?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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 配置数据库相关 事务 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/db_stu?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai"></property>
<property name="username" value="root" ></property>
<property name="password" value="333666999520"></property>
<property name="maxActive" value="10" ></property>
<property name="maxIdle" value="6"></property>
</bean>
<!-- 配置事务管理器 txManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">
</property>
</bean>
<!-- 增加对事务的支持 tx命名空间-->
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="studentDao" class="com.test.dao.impl.StudentDaoImpl">
</bean>
<bean id="studentService" class="com.test.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!-- 前置通知类 -->
<bean id="logBefore" class="com.test.aop.LogBefore">
</bean>
<!-- 后置通知类 -->
<bean id="logAfter" class="com.test.aop.LogAfter"></bean>
<!-- 异常通知类 -->
<bean id="logException" class="com.test.aop.LogException"></bean>
<bean id="logAround" class="com.test.aop.logAround"></bean>
<!-- 将addStudent()方法与通知关联 -->
<aop:config>
<!-- 配置切入点(在哪里执行通知) -->
<aop:pointcut expression="execution(public void com.test.service.impl.StudentServiceImpl.addStudent(com.test.entity.Student)) or execution(public void com.test.service.impl.StudentServiceImpl.deleteStudentById(int))" id="pointcut1"/>
<!-- 链接切入点与切面 -->
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut1"/>
</aop:config>
<aop:config>
<aop:pointcut expression="execution(public void com.test.service.impl.StudentServiceImpl.updateStudent(com.test.entity.Student))" id="pointcut2"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="pointcut2"/>
</aop:config>
<aop:config>
<aop:pointcut expression="execution(public void com.test.service.impl.StudentServiceImpl.addStudent(com.test.entity.Student))" id="pointcut3"/>
<aop:advisor advice-ref="logException" pointcut-ref="pointcut3"/>
</aop:config>
<aop:config>
<aop:pointcut expression="execution(public void com.test.service.impl.StudentServiceImpl.addStudent(com.test.entity.Student))" id="pointcut4"/>
<aop:advisor advice-ref="logAround" pointcut-ref="pointcut4"/>
</aop:config>
测试:
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService studentService = (StudentService)context.getBean("studentService");
studentService.addStudent(new Student());
studentService.deleteStudentById(1);
studentService.updateStudent(new Student());
}
}
前置通知!!!
环绕通知 - 前置通知
增加学生
环绕通知 - 后置通知
前置通知!!!
模拟删除...
更新学生信息...
后置通知:1.目标对象:com.test.service.impl.StudentServiceImpl@5fd4f8f5
2.参数个数:1
3.方法名:updateStudent
4.返回值:null