Bean的Scope
Scope描述的是Spring容器如何新建Bean的实例的。Spring的Scope有以下几种,通过@Scope注解来实现:
- Singleton:一个Spring容器中只要一个Bean的实例,此为默认配置,全容器共享一个实例。
- Prototype:每次调用新建一个Bean实例。
- Request:Web项目中,给每一个http request新建一个Bean实例。
- Session:Web项目中,给每一个http session新建一个Bean实例。
DemoSingletonService.java
@Service
public class DemoSingletonService { //默认为Singleton,相当于@Scope("singleton")。
}
DemoPrototypeService.java
@Service
@Scope("prototype")
public class DemoPrototypeService {
}
ScopeConfig.java
@Configuration
@ComponentScan("扫描的包")
public class ScopeConfig {
}
TestScope.java
public class TestScope{
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));
}
}
Spring EL和资源调用
Spring 开发中经常涉及调用各种资源的情况,包括普通文件、网址、配置文件、系统环境变量等,我们可以使用Spring 的表达式语言实现资源的注入。
Spring 主要在注解@Value的参数中使用表达式。
test.properties
book.author=yangdong
book.name=spring boot
DemoService.java
@Service
public class DemoService {
@Value("其他类的属性")
private String another;
public String getAnother() {
return another;
}
public void setAnother(String another) {
this.another = another;
}
}
test.txt
this is a test of @Value.
SpringEL.java
@Configuration
@ComponentScan("test")
@PropertySource("test/test.properties") //注入配置文件
public class SpringEL{
//注入普通字符串
@Value("I Love you")
private String normal;
//注入操作系统属性
@Value("#{systemProperties['os.name']}")
private String osName;
//注入表达式结果
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;
//注入其他Bean属性
@Value("#{demoService.another}")
private String fromAnother;
//注入文件资源
@Value("classpath:test/test.txt")
private Resource testFile;
//注入网址资源
@Value("http://www.baidu.com")
private Resource testUrl;
/**
* 注入配置文件(注入配置文件 需要使用@PropertySource指定文件地址,若使用@Value注入,则要配置一个
* PropertySourcesPlaceholderConfigurer的Bean.
* 注入Properties还可以从Environment中获得。
*/
@Value("${book.name}")
private String bookName;
//注入Properties还可以从Environment中获得
@Autowired
private Environment environment;
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
public void outputResource() throws IOException
{
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"));
}
}
TestSpringEL.java
public class TestSpringEL{
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringEL.class);
SpringEL el = context.getBean(SpringEL.class);
el.outputResource();
context.close();
}
}
Bean的初始化和销毁
实际开发的时候,经常会遇到在Bean使用之前或之后做些必要的操作,Spring对Bean的生命周期的操作提供了支持。在使用Java配置和注解配置下提供了如下两种方式:
- Java配置方式:使用@Bean的initMethod 和 destroyMethod;
- 注解方式:JSR-250的@PostConstruct 和 @PreDestroy;
BeanWay.java
public class BeanWay {
public void init()
{
System.out.println("@Bean-init-method");
}
public BeanWay()
{
super();
System.out.println("初始化构造函数-BeanWay");
}
public void destroy()
{
System.out.println("@Bean-destroy-method");
}
}
JSR250Way.java
public class JSR250Way {
@PostConstruct //在构造函数执行完之后执行
public void init()
{
System.out.println("JSR250-init-method");
}
public JSR250Way()
{
super();
System.out.println("初始化构造函数-JSR250Way");
}
@PreDestroy //在Bean销毁之前执行
public void destroy()
{
System.out.println("JSR250-destroy-method");
}
}
PrePostConfig.java
@Configuration
@ComponentScan("test")
public class PrePostConfig {
@Bean(initMethod="init",destroyMethod="destroy")
BeanWay beanWay()
{
return new BeanWay();
}
@Bean
JSR250Way jsr250Way ()
{
return new JSR250Way();
}
}
TestPrePost.java
public class TestPrePost{
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrePostConfig.class);
BeanWay beanWay = context.getBean(BeanWay.class);
JSR250Way jsr250Way = context.getBean(JSR250Way.class);
context.close();
}
}
事件
Spring的事件(Application Event)为Bean与Bean之间的消息通信提供了支持。当一个Bean处理完一个任务之后,希望另外一个Bean知道并能做相应的处理,这时我们就需要让另外一个Bean监听当前Bean所发送的事件。
Spring的事件需要遵循如下流程:
- 自定义事件,继承ApplicationEvent;
- 定义事件监听器,实现ApplicationListener;
- 使用容器发布事件;
DemoEvent.java
public class DemoEvent extends ApplicationEvent{
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;
}
}
DemoListener.java
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{ //实现ApplicationListener接口,并指定监听的事件类型
@Override
public void onApplicationEvent(DemoEvent event) { //使用onApplicationEvent方法对消息进行处理
String msg = event.getMsg();
System.out.println("我(bean-demoListener)接收到了bean-demoPublisher发布的消息:"+msg);
}
}
DemoPublisher.java
@Component
public class DemoPublisher {
@Autowired
ApplicationContext applicationContext;
public void publish(String msg) { //使用ApplicationContext 的publish方法来发布。
applicationContext.publishEvent(new DemoEvent(this, msg));
}
}
EventConfig.java
@Configuration
@ComponentScan("test")
public class EventConfig {
}
TestApplicationEvent.java
public class TestApplicationEvent{
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();
}
}
参考书籍:Spring Boot 实战
以上只是学习所做的笔记, 以供日后参考。如有错误请指正,谢谢啦!!!