原教程: https://www.w3cschool.cn/wkspring/
spring中的事件处理
如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。
标准事件:
|
Spring 的事件处理是单线程的
监听上下文标准事件:
- 创建实现ApplicationListener接口的事件处理类,并在接口方法onApplicationEvent()中实现接收到事件的逻辑
- 将事件处理类声明为bean
- 事件处理类无需其他类继承,当applicationContext发生变化时事件自动激活。
spring自定义事件
- class CustomEvent extends ApplicationEvent
- class CustomEventPublisher implements ApplicationEventPublisherAware
- class CustomEventHandler implements ApplicationListener<CustomEvent>
- 在beans.xml中将CustomEventPublisher ,CustomEventHandler声明为bean
- 当调用ApplicationEventPublisher的publishEvent(CustomEvent)时,自定义事件被激活
1 // CustomEvent.java 2 public class CustomEvent extends ApplicationEvent{ 3 4 public CustomEvent(Object source) { 5 super(source); 6 } 7 8 public String toString() { 9 return "My Custom Event"; 10 } 11 12 } 13 14 // CustomEventHandler .java 15 public class CustomEventHandler implements ApplicationListener<CustomEvent> { 16 17 @Override 18 public void onApplicationEvent(CustomEvent arg0) { 19 System.err.println(arg0.toString()); 20 } 21 22 } 23 24 // CustomEventPublisher.java 25 public class CustomEventPublisher implements ApplicationEventPublisherAware{ 26 private ApplicationEventPublisher publisher; 27 28 @Override 29 public void setApplicationEventPublisher(ApplicationEventPublisher arg0) { 30 this.publisher = arg0; 31 } 32 33 public void publish() { 34 CustomEvent ce = new CustomEvent(this); 35 publisher.publishEvent(ce); 36 } 37 38 } 39 40 // MainApp.java 41 public class MainApp { 42 public static void main(String[] args) { 43 ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 44 CustomEventPublisher publisher = (CustomEventPublisher) context.getBean("customEventPublisher"); 45 publisher.publish(); 46 publisher.publish(); 47 } 48 } 49 50 // beans.xml 51 <bean id="customEventPublisher" class="com.tutorialspoint.CustomEventPublisher"></bean> 52 <bean id="CustomEventHandler" class="com.tutorialspoint.CustomEventHandler"></bean>
spring框架的AOP
通知 | 描述 |
---|---|
前置通知 | 在一个方法执行之前,执行通知。 |
后置通知 | 在一个方法执行之后,不考虑其结果,执行通知。 |
返回后通知 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 |
抛出异常后通知 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 |
环绕通知 | 在建议方法调用之前和之后,执行通知。 |
1. spring中基于AOP的xml架构
重点是beans.xml文件
- <aop:config>标签
- <aop:aspect id="" ref="某个bean-id">
- <aop:pointcut expression="execution(* com.tutorialspoint.*.*(..))" id="pointcut-id">
- <aop:before method="" pointcut-ref="pointcut-id">
- <aop:after method="" pointcut-ref="pointcut-id">
- <aop:after-returning method="" pointcut-ref="pointcut-id" returning="">
- <aop:after-throwing method="" pointcut-ref="pointcut-id" throwing="" >
returning与throwing要指定method中返回的对象,拼写要一致
1 // beans.xml 2 <?xml version="1.0" encoding="UTF-8"?> 3 <beans 4 xmlns="http://www.springframework.org/schema/beans" 5 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xsi:schemaLocation="http://www.springframework.org/schema/beans 8 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 9 http://www.springframework.org/schema/aop 10 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> 11 12 <aop:config> 13 <aop:aspect id="log" ref="logging"> 14 <aop:pointcut expression="execution(* com.tutorialspoint.*.*(..))" id="selectAll"/> 15 <aop:before method="beforeAdvice" pointcut-ref="selectAll"/> 16 <aop:after method="afterAdvice" pointcut-ref="selectAll"/> 17 <aop:after-returning 18 method="afterReturningAdvice" 19 returning="retVal" 20 pointcut-ref="selectAll"/> 21 <aop:after-throwing 22 method="afterThrowingAdvice" 23 throwing="excep" 24 pointcut-ref="selectAll"/> 25 </aop:aspect> 26 </aop:config> 27 28 <bean id="student" class="com.tutorialspoint.Student"> 29 <property name="name" value="Zara"/> 30 <property name="age" value="11"/> 31 </bean> 32 33 <bean id="course" class="com.tutorialspoint.Course"> 34 <property name="courseName" value="English"/> 35 <property name="courseId" value="12"/> 36 </bean> 37 38 <bean id="logging" class="com.tutorialspoint.Logging"/> 39 40 </beans> 41 42 // Logging.java 43 public class Logging { 44 public void beforeAdvice() { 45 System.out.println("Going to setup student profile."); 46 } 47 public void afterAdvice() { 48 System.out.println("Student profile has been setup."); 49 } 50 public void afterReturningAdvice(Object retVal) { 51 System.out.println("Returning:"+retVal.toString()); 52 } 53 public void afterThrowingAdvice(IllegalArgumentException excep) { 54 System.out.println("There has been an exception: "+excep.toString()); 55 } 56 57 } 58 59 // Student.java 60 public class Student { 61 private Integer age; 62 private String name; 63 public Integer getAge() { 64 System.out.println("Studetn getAge() Age : " + age ); 65 return age; 66 } 67 public void setAge(Integer age) { 68 this.age = age; 69 } 70 public String getName() { 71 System.out.println("Student getName() Name : " + name ); 72 return name; 73 } 74 public void setName(String name) { 75 this.name = name; 76 } 77 public void printThrowException() { 78 System.out.println("Student printThrowException() Exception raised"); 79 throw new IllegalArgumentException(); 80 } 81 } 82 83 // Course.java 84 public class Course { 85 String courseName; 86 int courseId; 87 public String getCourseName() { 88 System.out.println("Course getCouseName() "+courseName); 89 return courseName; 90 } 91 public void setCourseName(String courseName) { 92 System.out.println("Course setCourseName() "+courseName); 93 this.courseName = courseName; 94 } 95 public int getCourseId() { 96 System.out.println("Couse getCourseId() "+courseId); 97 return courseId; 98 } 99 public void setCourseId(int courseId) { 100 System.out.println("Course setCouseId() "+courseId); 101 this.courseId = courseId; 102 } 103 } 104 105 //MainApp.java 106 public class MainApp { 107 public static void main(String[] args) { 108 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 109 Student student = (Student) context.getBean("student"); 110 student.getName(); 111 student.getAge(); 112 113 Course course = (Course) context.getBean("course"); 114 course.getCourseName(); 115 course.getCourseId();
// 出现此异常的原因是setCourseName()返回值是void类型。spring的afterReturningAdvice(object retVal)中的参数是setCourseName()的返回值 116 course.setCourseName("math"); 会报空指针异常 117 course.setCourseId(15); 118 119 student.printThrowException(); 120 } 121 }
运行结果:
Course setCourseName() English
Course setCouseId() 12
Going to setup student profile.
Student getName() Name : Zara
Student profile has been setup.
Returning:Zara
Going to setup student profile.
Studetn getAge() Age : 11
Student profile has been setup.
Returning:11
Going to setup student profile.
Course getCouseName() English
Student profile has been setup.
Returning:English
Going to setup student profile.
Couse getCourseId() 12
Student profile has been setup.
Returning:12
Going to setup student profile.
Course setCouseId() 15
Student profile has been setup.
Exception in thread "main" java.lang.NullPointerException
其中的Logging类定义了<aop:advice>的method
<aop:pointcut expression="execution(* com.tutorialspoint.*.*(..))"作用于beans.xml中下student bean之外的bean的所有方法,即student bean和coursebean
也可以指定
expression="execution(* com.tutorialspoint.Student.getName(..))"只作用于Student类下的getName()
2. spring中基于AOP的@AspectJ
- @Aspect注解Logging类,类中方法注解为Advice方法。注意@Pointcut声明一个函数为切入点,函数名类似于xml方式中切入点的id。
- 在beans.xml中添加<aop:aspectj-autoproxy/>,而省去了xml方式中<sop:config>的一大坨配置。
1 // Logging.java 2 @Aspect 3 public class Logging { 4 @Pointcut("execution(* com.tutorialspoint.*.*(..))") 5 private void selectAll() { 6 7 } 8 @Before("selectAll()") 9 public void beforeAdvice() { 10 System.out.println("Logging beforeAdvice()"); 11 } 12 @After("selectAll()") 13 public void afterAdvice() { 14 System.out.println("Logging afterAdvice()"); 15 } 16 @AfterReturning(pointcut="selectAll()", returning="retVal") 17 public void afterReturningAdvice(Object retVal) { 18 System.out.println("Logging afterReturningAdvice():"+retVal.toString()+" "); 19 } 20 @AfterThrowing(pointcut="selectAll()", throwing="excep") 21 public void afterThrowingAdvice(IllegalArgumentException excep) { 22 System.out.println("Logging afterThrowingAdvice()"+excep.toString()); 23 } 24 25 } 26 27 // Student.java 28 public class Student { 29 private Integer age; 30 private String name; 31 public Integer getAge() { 32 System.out.println("Studetn getAge() Age : " + age ); 33 return age; 34 } 35 public int setAge(Integer age) { 36 System.out.println("Student setAge() "+ age); 37 this.age = age; 38 return age; 39 } 40 public String getName() { 41 System.out.println("Student getName() Name : " + name ); 42 return name; 43 } 44 public String setName(String name) { 45 System.out.println("Student setName() "+name); 46 this.name = name; 47 return name; 48 } 49 public void printThrowException() { 50 System.out.println("Student printThrowException() Exception raised"); 51 throw new IllegalArgumentException(); 52 } 53 } 54 55 // Course.java 56 public class Course { 57 String courseName; 58 int courseId; 59 public String getCourseName() { 60 System.out.println("Course getCouseName() "+courseName); 61 return courseName; 62 } 63 public String setCourseName(String courseName) { 64 System.out.println("Course setCourseName() "+courseName); 65 this.courseName = courseName; 66 return courseName; 67 } 68 public int getCourseId() { 69 System.out.println("Couse getCourseId() "+courseId); 70 return courseId; 71 } 72 public int setCourseId(int courseId) { 73 System.out.println("Course setCouseId() "+courseId); 74 this.courseId = courseId; 75 return courseId; 76 } 77 } 78 79 //MainApp.java 80 public class MainApp { 81 public static void main(String[] args) { 82 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); 83 Student student = (Student) context.getBean("student"); 84 student.getName(); 85 student.getAge(); 86 student.setAge(5); 87 student.setName("zhangfan"); 88 89 Course course = (Course) context.getBean("course"); 90 course.getCourseName(); 91 course.getCourseId(); 92 course.setCourseName("math"); 93 course.setCourseId(15); 94 95 student.printThrowException(); 96 } 97 } 98 99 // beans.xml 100 <aop:aspectj-autoproxy/> 101 102 <bean id="student" class="com.tutorialspoint.Student"> 103 <property name="name" value="Zara"/> 104 <property name="age" value="11"/> 105 </bean> 106 107 <bean id="course" class="com.tutorialspoint.Course"> 108 <property name="courseName" value="English"/> 109 <property name="courseId" value="12"/> 110 </bean> 111 112 <bean id="logging" class="com.tutorialspoint.Logging"/>
运行结果: Student setName() Zara Student setAge() 11 Course setCourseName() English Course setCouseId() 12 Logging beforeAdvice() Student getName() Name : Zara Logging afterAdvice() Logging afterReturningAdvice():Zara Logging beforeAdvice() Studetn getAge() Age : 11 Logging afterAdvice() Logging afterReturningAdvice():11 Logging beforeAdvice() Student setAge() 5 Logging afterAdvice() Logging afterReturningAdvice():5 Logging beforeAdvice() Student setName() zhangfan Logging afterAdvice() Logging afterReturningAdvice():zhangfan Logging beforeAdvice() Course getCouseName() English Logging afterAdvice() Logging afterReturningAdvice():English Logging beforeAdvice() Couse getCourseId() 12 Logging afterAdvice() Logging afterReturningAdvice():12 Logging beforeAdvice() Course setCourseName() math Logging afterAdvice() Logging afterReturningAdvice():math Logging beforeAdvice() Course setCouseId() 15 Logging afterAdvice() Logging afterReturningAdvice():15 Logging beforeAdvice() Student printThrowException() Exception raised Logging afterAdvice() Logging afterThrowingAdvice()java.lang.IllegalArgumentException
小结:
- xml方式:切入点及Advice方法的指定在beans.xml的<aop:config>元素中;
- @AspectJ方式:切入点及Advice方法的指定在类中;beans.xml中添加<aop:aspectj-autoproxy/>启动AspectJ方式。
- afterReturningAdvice(object retVal)要求切入点expression中所有的方法都要有返回值,不能是void,否则报参数错误异常。
- afterThrowingAdvice()不要求切入点expression中所有方法的返回值可以为void。
- 五种通知类型,分别代表着在pointcut expression指定方法的前后要调用Advice方法