Spring(二)

原教程: https://www.w3cschool.cn/wkspring/

spring中的事件处理

如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。

标准事件:


 

标准事件 激活时机
ContextRefreshedEvent ApplicationContext 被初始化或刷新时,或调用ConfigurableApplicationContext接口的refresh()
ContextStartedEvent 调用ConfigurableApplicationContext接口的start()时
ContextStoppedEvent 调用ConfigurableApplicationContext接口的stop()时
ContextClosedEvent 调用ConfigurableApplicationContext接口的close()时
RequestHandledEvent 暂无

 

 

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()+"\n");
 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方法

 

posted @ 2019-04-07 22:46  赤云封天  阅读(241)  评论(0编辑  收藏  举报