SSM项目从零开始到入门042-Spring使用注解来配置依赖注入

从 Spring 2.5 开始就可以使用注解来配置依赖注入。而不是采用 XML 来描述一个 bean 连线,你可以使用相关类,方法或字段声明的注解,将 bean 配置移动到组件类本身。
在 XML 注入之前进行注解注入,因此后者的配置将通过两种方式的属性连线被前者重写。

注解连线在默认情况下在 Spring 容器中不打开。因此,在可以使用基于注解的连线之前,我们将需要在我们的 Spring 配置文件中启用它。所以如果你想在 Spring 应用程序中使用的任何注解,可以考虑到下面的配置文件。

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

</beans>

一旦 被配置后,你就可以开始注解你的代码,表明 Spring 应该自动连接值到属性,方法和构造函数。让我们来看看几个重要的注解,并且了解它们是如何工作的:

1.@Required

@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

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   
   <bean id="user" class="com.lcx.pojo.User">
      <property name="name"  value="落尘曦" />
      <!-- <property name="pwd"  value="123456" /> -->
   </bean>
   
</beans>

我们现将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实例失败。我们将上面的注释打开然后执行测试代码。


程序打印出我们设置的信息。


2.@Autowired

@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文件

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   
   <bean id="user" class="com.lcx.pojo.User">
      <property name="name"  value="落尘曦" />
      <property name="pwd"  value="123456" />
   </bean>
   
   <bean id="dept" class="com.lcx.pojo.Dept"></bean>
   
</beans>

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) 选项关闭默认行为。

3.@Qualifier

当你创建多个具有相同类型的 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配置文件

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>
   
   <bean id="user1" class="com.lcx.pojo.User">
      <property name="name"  value="落尘曦" />
      <property name="pwd"  value="123456" />
   </bean>
   
   <bean id="user2" class="com.lcx.pojo.User">
      <property name="name"  value="落尘曦" />
      <property name="pwd"  value="654321" />
   </bean>
   
   <bean id="dept" class="com.lcx.pojo.Dept"></bean>
   
</beans>

这里我们定义两个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的内容。

4.JSR-250 Annotations
Spring还使用基于 JSR-250 注释,它包括 @PostConstruct, @PreDestroy 和 @Resource 注释。
@PostConstruct 和 @PreDestroy 注释:
为了定义一个 bean 的安装和卸载,我们使用 init-method 和/或 destroy-method 参数简单的声明一下 。init-method 属性指定了一个方法,该方法在 bean 的实例化阶段会立即被调用。同样地,destroy-method 指定了一个方法,该方法只在一个 bean 从容器中删除之前被调用。

使用 @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销毁执行");
	}
}
5.Spring 基于 Java 的配置
基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大多数的 Spring。
@Configuration 和 @Bean 注解
带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。
@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
最简单可行的 @Configuration 类如下所示:

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中配置了:

<beans>
   <bean id="user" class="com.lcx.User" />
</beans>

测试类:
@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() );
	} 


6.Spring 中的事件处理

    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 的事件处理是单线程的,所以如果一个事件被发布,直至并且除非所有的接收者得到的该消息,该进程被阻塞并且流程将不会继续。因此,如果事件处理被使用,在设计应用程序时应注意。

监听上下文事件
为了监听上下文事件,一个 bean 应该实现只有一个方法 onApplicationEvent() 的 ApplicationListener 接口。
下面的例子来看看事件是如何传播的,以及如何可以用代码来执行基于某些事件所需的任务。

新建类StartEventHandler

package com.lcx.pojo;

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;

public class StartEventHandler implements ApplicationListener<ContextStartedEvent>{

	@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<ContextStoppedEvent>{

	@Override
	public void onApplicationEvent(ContextStoppedEvent event) {
		System.out.println("StopEventHandler执行");
	}

	
}

编辑xml文件:

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   
    <bean id="startEventHandler" class="com.lcx.pojo.StartEventHandler" ></bean> 
    
    <bean id="stopEventHandler" class="com.lcx.pojo.StopEventHandler" ></bean> 
 
   	<bean id="user" class="com.lcx.pojo.User" >
       <property name="name" value="落尘曦"/>
       <property name="pwd" value="123456"/>
    </bean> 
    
</beans>

编辑测试类测试输出。

@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();
	} 



Spring 中的自定义事件

通过扩展 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<UserEvent>{
   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

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   
    <bean id="userEventHandler" class="com.lcx.pojo.UserEventHandler"/>

    <bean id="userEventPublisher" class="com.lcx.pojo.UserEventPublisher"/>
    
</beans>

5.编辑测试类测试输出

@Test
	public void test() {
	   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
	   UserEventPublisher user = (UserEventPublisher) context.getBean("userEventPublisher");
	   user.publish();
	   user.publish();
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心歌技术

打赏不能超过你的早餐钱!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值