2.1 Bean的Scope
2.1.1简介
Scope描述的是Spring容器如何新建Bean的实例的。Spring的Scope有以下几种,通过@Scope注解来实现。
(1)Singleton:一个Spring容器中只有一个Bean的实例,此为Spring的默认配置,全容器共享一个实例。
(2)Prototype:每次调用新建一个Bean的实例。
(3)Request:Web项目中,给每一个http request新建一个Bean实例。
(4)Session:Web项目中,给每一个http session新建一个Bean实例。
(5)GlobalSession:这个只在portal应用中有用,给每一个global http session新建一个Bean实例。
示例
(1)编写Singleton的Bean
package com.wisely.highlight_spring4.ch2.scope;
@Service //1
public class DemoSingletonService {
}
①默认为Singleton,相当于@Scope(“singleton”)。
(2)编写Prototype的Bean
package com.wisely.highlight_spring4.ch2.scope;
@Service
@Scope("prototype")//1
public class DemoPrototypeService {
}
①声明Scope为Prototype。
(3)配置类
package com.wisely.highlight_spring4.ch2.scope;
@Configuration
@ComponentScan("com.wisely.highlight_spring4.ch2.scope")
public class ScopeConfig {
}
(4)运行
package com.wisely.highlight_spring4.ch2.scope;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScopeConfig.class);
DemoSingletonService s1 = context.getBean(DemoSingletonService.class);
DemoSingletonService s2 = context.getBean(DemoSingletonService.class);
DemoPrototypeService p1 = context.getBean(DemoPrototypeService.class);
DemoPrototypeService p2 = context.getBean(DemoPrototypeService.class);
System.out.println("s1与s2是否相等:"+s1.equals(s2));
System.out.println("p1与p2是否相等:"+p1.equals(p2));
context.close();
}
}
(5)结果
s1与s2是否相等:true
p1与p2是否相等:false
2.2 Spring EL和资源调用
Spring EL:Spring表达式语言,支持在xml和注解中使用表达式
Spring开发中经常涉及调用各种资源的情况,包含普通文件、网址、配置文件、系统环境变量等,我们可以使用Spring的表达式语言实现资源的注入。
Spring主要在注解@Value的参数中使用表达式。
示例
(1)准备,增加commons-io可简化文件相关操作
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
在com.wisely.highlight_spring4.ch2.el包下新建test.txt,内容随意。
在com.wisely.highlight_spring4.ch2.el包下新建test.properties,内容如下:
book.author=wangyunfei
book.name=spring boot
(2)需被注入的Bean
package com.wisely.highlight_spring4.ch2.el;
@Service
public class DemoService {
@Value("其他类的属性") //1
private String another;
public String getAnother() {
return another;
}
public void setAnother(String another) {
this.another = another;
}
}
①此处为注入普通字符串
(3)演示配置类
package com.wisely.highlight_spring4.ch2.el;
@Configuration
@ComponentScan("com.wisely.highlight_spring4.ch2.el")
@PropertySource("classpath:com/wisely/highlight_spring4/ch2/el/test.properties")//7
public class ElConfig {
@Value("I Love You!") //1
private String normal;
@Value("#{systemProperties['os.name']}") //2
private String osName;
@Value("#{ T(java.lang.Math).random() * 100.0 }") //3
private double randomNumber;
@Value("#{demoService.another}") //4
private String fromAnother;
@Value("classpath:com/wisely/highlight_spring4/ch2/el/test.txt") //5
private Resource testFile;
@Value("http://www.baidu.com") //6
private Resource testUrl;
@Value("${book.name}") //7
private String bookName;
@Autowired
private Environment environment; //7
@Bean //7
public static PropertySourcesPlaceholderConfigurer propertyConfigure() {
return new PropertySourcesPlaceholderConfigurer();
}
public void outputResource() {
try {
System.out.println(normal);
System.out.println(osName);
System.out.println(randomNumber);
System.out.println(fromAnother);
System.out.println(IOUtils.toString(testFile.getInputStream()));
System.out.println(IOUtils.toString(testUrl.getInputStream()));
System.out.println(bookName);
System.out.println(environment.getProperty("book.author"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
①注入普通字符串。
②注入操作系统属性。
③注入表达式结果。
④注入其他Bean属性。
⑤注入文件资源。
⑥注入网址资源。
⑦注入配置文件。
注入配置配件需使用@PropertySource指定文件地址,若使用@Value注入,则要配置一个PropertySourcesPlaceholderConfigurer的Bean。注意,@Value("({book.name}")使用的是“)”,而不是“#”。
注入Properties还可从Environment中获得。
(4)运行
package com.wisely.highlight_spring4.ch2.el;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ResourceConfig.class);
ElConfig resourceService = context.getBean(ElConfig.class);
resourceService.outputResource();
context.close();
}
}
(5)结果
I Love You!
Windows 10.0
32.2342342345435345234234
其他类的属性
测试文件
<!D..................
2.3 Bean的初始化和销毁
经常会遇到在Bean在使用之前或者之后做些必要的操作,Spring对Bean的生命周期的操作提供了支持。
在使用Java配置和注解配置下提供如下两种方式:
(1)Java配置方式:使用@Bean的initMethod和destroyMethod(相当于xml配置的init-method和destory-method)。
(2)注解方式:利用JSR-250的@PostConstruct和@PreDestroy。
示例
(1)增加JSR250支持
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
(2)使用@Bean形式的Bean
package com.wisely.highlight_spring4.ch2.prepost;
public class BeanWayService {
public void init(){
System.out.println("@Bean-init-method");
}
public BeanWayService() {
super();
System.out.println("初始化构造函数-BeanWayService");
}
public void destroy(){
System.out.println("@Bean-destory-method");
}
}
(3)使用JSR250形式的Bean
package com.wisely.highlight_spring4.ch2.prepost;
public class JSR250WayService {
@PostConstruct //1
public void init(){
System.out.println("jsr250-init-method");
}
public JSR250WayService() {
super();
System.out.println("初始化构造函数-JSR250WayService");
}
@PreDestroy //2
public void destroy(){
System.out.println("jsr250-destory-method");
}
}
①@PostConstruct,在构造函数执行完之后执行。
②@PreDestroy,在Bean销毁之前执行。
(4)配置类
package com.wisely.highlight_spring4.ch2.prepost;
@Configuration
@ComponentScan("com.wisely.highlight_spring4.ch2.prepost")
public class PrePostConfig {
@Bean(initMethod="init",destroyMethod="destroy") //1
BeanWayService beanWayService(){
return new BeanWayService();
}
@Bean
JSR250WayService jsr250WayService(){
return new JSR250WayService();
}
}
①initMethod和destroyMethod指定BeanWayService类的init和destroy方法在构造之后、Bean销毁之前执行。
(5)运行
package com.wisely.highlight_spring4.ch2.prepost;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrePostConfig.class);
BeanWayService beanWayService = context.getBean(BeanWayService.class);
JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class);
context.close();
}
}
(6)结果
初始化构造函数-BeanWayService
@Bean-init-method
初始化构造函数-JSR250WayService
jsr250-init-method
jsr250-destory-method
@Bean-destory-method
2.4 Profile
Profile为在不同环境下使用不同的配置提供了支持(开发环境下的配置和生产环境下的配置肯定是不同的,例如,数据库的配置)。
(1)通过设定Environment的ActiveProfiles来设定当前context需要使用的配置环境。在开发中使用@Profile注解类或者方法,达到在不同情况下选择实例化不同的Bean。
(2)通过设定jvm的spring.profiles.active参数来设置配置环境。
(3)Web项目设置在Servlet的context parameter中。
示例
(1)示例Bean
package com.wisely.highlight_spring4.ch2.profile;
public class DemoBean {
private String content;
public DemoBean(String content) {
super();
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
(2)Profile配置
package com.wisely.highlight_spring4.ch2.profile;
@Configuration
public class ProfileConfig {
@Bean
@Profile("dev") //1
public DemoBean devDemoBean() {
return new DemoBean("from development profile");
}
@Bean
@Profile("prod") //2
public DemoBean prodDemoBean() {
return new DemoBean("from production profile");
}
}
①Profile为dev时实例化devDemoBean。
②Profile为prod时实例化prodDemoBean。
(3)运行
package com.wisely.highlight_spring4.ch2.profile;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("prod"); //1
context.register(ProfileConfig.class);//2
context.refresh(); //3
DemoBean demoBean = context.getBean(DemoBean.class);
System.out.println(demoBean.getContent());
context.close();
}
}
①先将活动的Profile设置为prod。
②后置注册Bean配置类,不然会报Bean未定义的错误。
③刷新容器。
(4)结果
from production profile
2.5事件(Application Event)
Spring的事件(Application Event)为Bean与Bean之间的消息通信提供了支持。当一个Bean处理完一个任务之后,希望另外一个Bean知道并能做相应的处理,这时我们就需要让另外一个Bean监听当前Bean所发送的事件。
Spring的事件需要遵循如下流程:
(1)自定义事件,集成ApplicationEvent。
(2)定义事件监听器,实现ApplicationListener。
(3)使用容器发布事件。
示例
(1)自定义事件
package com.wisely.highlight_spring4.ch2.event;
public class DemoEvent extends ApplicationEvent{
private static final long serialVersionUID = 1L;
private String msg;
public DemoEvent(Object source,String msg) {
super(source);
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
(2)事件监听器
package com.wisely.highlight_spring4.ch2.event;
@Component
public class DemoListener implements ApplicationListener<DemoEvent> {//1
public void onApplicationEvent(DemoEvent event) {//2
String msg = event.getMsg();
System.out.println("我(bean-demoListener)接收到了bean-demoPublisher发布的消息:"+ msg);
}
}
①实现ApplicationListener接口,并指定监听的事件类型。
②使用onApplicationEvent方法对消息进行接受处理。
(3)事件发布类
package com.wisely.highlight_spring4.ch2.event;
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext; //1
public void publish(String msg){
applicationContext.publishEvent(new DemoEvent(this, msg)); //2
}
}
①注入ApplicationContext用来发布事件。
②使用ApplicationContext的publishEvent方法来发布。
(4)配置类
package com.wisely.highlight_spring4.ch2.event;
@Configuration
@ComponentScan("com.wisely.highlight_spring4.ch2.event")
public class EventConfig {
}
(5)运行
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class);
DemoPublisher demoPublisher = context.getBean(DemoPublisher.class);
demoPublisher.publish("hello application event");
context.close();
}
}
(6)结果
我(bean-demoListener)接收到了bean-demoPublisher发布的消息:hello application event