注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。
一旦 被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。让我们来看看几个重要的注解,并且了解它们是如何工作的:
@Required 注解应用于 bean 属性的 setter 方法。它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。下面显示的是一个使用 @Required 注释的示例。
1.新建一个工程
2.在目录src/main/java新建包com.lcx.pojo并新建User.java 在set方法指定@Required
package com.lcx.pojo;
import org.springframework.beans.factory.annotation.Required;
public class User {
private String name;
private String pwd;
public String getName() {
return name;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
@Required
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
3.新建beans.xml并配置User
我们现将pwd属性注释掉
4.新建测试类测试运行
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
System.out.println("name: " + user.getName() );
System.out.println("pwd : " + user.getPwd() );
}
发现程序报Initialization of bean failed; nested exception is
org.springframework.beans.factory.BeanInitializationException: Property 'pwd' is required for bean 'user'
异常,即创建user实例失败。我们将上面的注释打开然后执行测试代码。
程序打印出我们设置的信息。
@Autowired 注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。当 Spring遇到一个在 setter 方法中使用的 @Autowired 注释,它会在方法中视图执行 byType 自动连接。
1.接着上边的例子我们在包com.lcx.pojo下创建Dept类,并指定@Autowired
package com.lcx.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class Dept {
private User user;
@Autowired
public Dept(User user){ //Dept带参构造函数
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
2.编辑xml文件
3.编辑测试类测试输出
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Dept dept = (Dept) context.getBean("dept");
System.out.println("name: " + dept.getUser().getName() );
System.out.println("pwd : " + dept.getUser().getPwd() );
}
可以看到程序输出了我们设置的值。
@Autowired 的(required=false)选项。默认情况下,@Autowired 注释意味着依赖是必须的,它类似于 @Required 注释,然而可以使用 @Autowired 的 (required=false) 选项关闭默认行为。
当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱。
1.接着上边的例子,我们修改Dept类
package com.lcx.pojo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Dept {
@Autowired
@Qualifier("user2")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
其中@Qualifier("user2")指定程序去寻找user2去装配
2.修改xml配置文件
这里我们定义两个user实例且名字不想同,属性值也不同
3.编辑测试代码测试运行
@Test
public void test2() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Dept dept = (Dept) context.getBean("dept");
System.out.println("name: " + dept.getUser().getName() );
System.out.println("pwd : " + dept.getUser().getPwd() );
}
可以看到程序输出了我我们设置的user2的内容。
使用 @PostConstruct 注释作为初始化回调函数的一个替代,@PreDestroy 注释作为销毁回调函数的一个替代。
package com.lcx.pojo;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Required;
public class User {
private String name;
private String pwd;
public String getName() {
return name;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
@Required
public void setPwd(String pwd) {
this.pwd = pwd;
}
@PostConstruct
public void init(){
System.out.println("bean初始化执行");
}
@PreDestroy
public void destroy(){
System.out.println("bean销毁执行");
}
}
User类:
package com.lcx.pojo;
public class User {
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
Dept类:
package com.lcx.pojo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Dept {
@Bean
public User getUser() {
return new User();
}
}
上面的代码相当于在xml中配置了:
@Test
public void test3() {
ApplicationContext context = new AnnotationConfigApplicationContext(Dept.class);
User user = context.getBean(User.class);
System.out.println("name: " + user.getName() );
System.out.println("pwd : " + user.getPwd() );
}
Spring 的核心是 ApplicationContext,它负责管理 beans 的完整生命周期。当加载 beans 时,ApplicationContext 发布某些类型的事件。例如,当上下文启动时,ContextStartedEvent 发布,当上下文停止时,ContextStoppedEvent 发布。
通过 ApplicationEvent 类和 ApplicationListener 接口来提供在 ApplicationContext 中处理事件。如果一个 bean 实现 ApplicationListener,那么每次 ApplicationEvent 被发布到 ApplicationContext 上,那个 bean 会被通知。
Spring 提供了以下的标准事件:
1.ContextRefreshedEvent
ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext 接口中使用 refresh() 方法来发生。
2.ContextStartedEvent
当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
3.ContextStoppedEvent
当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
4.ContextClosedEvent
当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
5.RequestHandledEvent
这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。
由于 Spring 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。
新建类StartEventHandler
package com.lcx.pojo;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
public class StartEventHandler implements ApplicationListener{
@Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("StartEventHandler执行");
}
}
新建类StopEventHandler:
package com.lcx.pojo;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;
public class StopEventHandler implements ApplicationListener{
@Override
public void onApplicationEvent(ContextStoppedEvent event) {
System.out.println("StopEventHandler执行");
}
}
编辑xml文件:
编辑测试类测试输出。
@Test
public void test4() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
((AbstractApplicationContext) context).start();
User user = (User) context.getBean("user");
System.out.println("name: " + user.getName() );
System.out.println("pwd : " + user.getPwd() );
((AbstractApplicationContext) context).stop();
}
通过扩展 ApplicationEvent,创建一个事件类。这个类必须定义一个默认的构造函数,它应该从 ApplicationEvent 类中继承的构造函数。
1.新建UserEvent.java
package com.lcx.pojo;
import org.springframework.context.ApplicationEvent;
public class UserEvent extends ApplicationEvent{
public UserEvent(Object source) {
super(source);
}
@Override
public String toString() {
return "UserEvent执行!";
}
}
2.新建UserEventHandler.java
package com.lcx.pojo;
import org.springframework.context.ApplicationListener;
public class UserEventHandler implements ApplicationListener{
public void onApplicationEvent(UserEvent event) {
System.out.println(event.toString());
}
}
3新建UserEventPublisher.java
package com.lcx.pojo;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class UserEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
public void setApplicationEventPublisher(ApplicationEventPublisher publisher){
this.publisher = publisher;
}
public void publish() {
UserEvent ue = new UserEvent(this);
publisher.publishEvent(ue);
}
}
4.编辑xml
5.编辑测试类测试输出
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserEventPublisher user = (UserEventPublisher) context.getBean("userEventPublisher");
user.publish();
user.publish();
}