Spring Boot實戰(2) Spring常用配置
1. Bean的Scope
scope描述Spring容器如何新建Bean的實例。通過註解@Scope實現,取值有:
a. Singleton:一個Spring容器中只有一個Bean的實例。此為Spring的默認配置,全容器共享一個實例。
b. Prototype:每次調用新建一個Bean的實例
c. Request:Web項目中,給每一個Http Request新建一個Bean實例
d. Session:Web項目中,給每一個Http Session新建一個Bean實例
e. GlobalSession:這個只在portal應用中有用,給每一個global http session新建一個Bean實例。
示例:演示Singleton和Prototype分別從Spring容器中獲取2次Bean,判斷Bean的實例是否相等
1) 編寫Singleton的Bean
1 package com.ws.study.scope; 2 3 import org.springframework.stereotype.Service; 4 5 // 默認為Singleton,等同於@Scope("singleton") 6 @Service 7 public class DemoSingletonService { 8 } 9View Code
2) 編寫Prototype的Bean
1 package com.ws.study.scope; 2 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 // 聲明為Prototype 8 @Scope(value = "prototype") 9 public class DemoPrototypeService { 10 }View Code
3) 配置類
1 package com.ws.study.scope; 2View Code3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.stereotype.Component; 5 6 @Component 7 @ComponentScan("com.ws.study.scope") 8 public class ScopeConfig { 9 } 10
4) 運行類
1 package com.ws.study.scope; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScopeConfig.class); 9 10 DemoSingletonService s1 = context.getBean(DemoSingletonService.class); 11 DemoSingletonService s2 = context.getBean(DemoSingletonService.class); 12 System.out.println("s1與s2是否相等:"+s1.equals(s2)); 13 14 DemoPrototypeService p1 = context.getBean(DemoPrototypeService.class); 15 DemoPrototypeService p2 = context.getBean(DemoPrototypeService.class); 16 System.out.println("p1與p2是否相等:"+p1.equals(p2)); 17 } 18 19 } 20View Code
5) 運行結果
1 五月 30, 2018 11:13:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@183da3f: startup date [Wed May 30 23:13:15 CST 2018]; root of context hierarchy 3 s1與s2是否相等:true 4 p1與p2是否相等:false 5 五月 30, 2018 11:13:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 6 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@183da3f: startup date [Wed May 30 23:13:15 CST 2018]; root of context hierarchy 7View Code
2. Spring EL和資源調用
Spring EL為Spring表達式語言,支持在xml和註解中使用表達式。Spring EL實現普通文件、網址、配置文件、系統環境變量等資源的註入。Spring主要在@Value的參數中使用表達式。
示例:
1) 加入commons-io依賴
1 <dependency> 2 <groupId>commons-io</groupId> 3 <artifactId>commons-io</artifactId> 4 <version>2.3</version> 5 </dependency>View Code
2) 包下創建text.txt,內容隨意,此示例寫入如下:
1 Spring
View Code
3) 包下新建test.properties
1 test.content=spring 2 test.date=2018View Code
4) 需被註入的Bean
1 package com.ws.study.el; 2 3 import org.springframework.beans.factory.annotation.Value; 4 import org.springframework.stereotype.Service; 5 6 @Service 7 public class DemoService { 8 // 註入普通字符串 9 @Value("其他類的屬性") 10 private String another; 11 12 public String getAnother() { 13 return another; 14 } 15 16 public void setAnother(String another) { 17 this.another = another; 18 } 19 } 20View Code
5) 配置類
1 package com.ws.study.el; 2 3 import org.apache.commons.io.IOUtils; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Value; 6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.ComponentScan; 8 import org.springframework.context.annotation.PropertySource; 9 import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 10 import org.springframework.core.env.Environment; 11 import org.springframework.core.io.Resource; 12 import org.springframework.stereotype.Component; 13 14 @Component 15 @ComponentScan("com.ws.study.el") 16 // 註入加載的配置文件 17 @PropertySource("classpath:com/ws/study/el/test.properties") 18 public class ElConfig { 19 20 // 註入普通字符串 21 @Value("I love you") 22 private String normal; 23 24 // 註入操作系統屬性 25 @Value("#{systemProperties[‘os.name‘]}") 26 private String osName; 27 28 // 註入表達式結果 29 @Value("#{ T(java.lang.Math).random() * 100.0 }") 30 private double randomNumber; 31 32 // 註入其他Bean屬性 33 @Value("#{demoService.another}") 34 private String fromAnother; 35 36 // 註入文件資源 37 @Value("classpath:com/ws/study/el/test.txt") 38 private Resource testFile; 39 40 // 註入Url 41 @Value("https://www.baidu.com") 42 private Resource testUrl; 43 44 // 註入配置文件 45 // 如果沒有上述的@PropertySource,而使用需要@Value加載配置文件,則需配置一個PropertySourcesPlaceholderConfigurer的Bean 46 @Value("${test.content}") 47 private String content; 48 49 // 註入配置文件也可以從Environment獲取 50 @Autowired 51 private Environment environment; 52 53 @Bean 54 public static PropertySourcesPlaceholderConfigurer propertyConfigure(){ 55 return new PropertySourcesPlaceholderConfigurer(); 56 } 57 58 public void outputResource(){ 59 try { 60 System.out.println(normal); 61 System.out.println(osName); 62 System.out.println(randomNumber); 63 System.out.println(fromAnother); 64 System.out.println(IOUtils.toString(testFile.getInputStream())); 65 System.out.println(IOUtils.toString(testUrl.getInputStream())); 66 System.out.println(content); 67 System.out.println(environment.getProperty("test.content")); 68 } catch (Exception e) { 69 } 70 } 71 } 72View Code
6) 運行類
1 package com.ws.study.el; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 public static void main(String[] args) { 7 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ElConfig.class); 8 ElConfig elConfig = context.getBean(ElConfig.class); 9 elConfig.outputResource(); 10 context.close(); 11 } 12 } 13View Code
7) 運行結果
1 五月 31, 2018 10:04:31 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1bc7afb: startup date [Thu May 31 22:04:31 CST 2018]; root of context hierarchy 3 I love you 4 Windows 7 5 81.51080310192492 6 其他類的屬性 7 Spring 8 <!DOCTYPE html> 9 <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus=autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn" autofocus></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新聞</a> <a href=https://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地圖</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>視頻</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>貼吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登錄</a> </noscript> <script>document.write(‘<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=‘+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ ‘" name="tj_login" class="lb">登錄</a>‘); 10 </script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多產品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關於百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必讀</a> <a href=http://jianyi.baidu.com/ class=cp-feedback>意見反饋</a> 京ICP證030173號 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html> 11 12 spring 13 spring 14 五月 31, 2018 10:07:34 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 15 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1bc7afb: startup date [Thu May 31 22:04:31 CST 2018]; root of context hierarchy 16View Code
3. Bean的初始化和銷毀
(1) Spring對Bean的生命周期的操作提供了支持。對於Java配置方式,使用@Bean的initMethod和destroyMethod(相當於xml配置的init-method和destory-method);對於註解方式,使用JSR-250的@PostConstruct和@PreDestroy
示例:
1) 增加JSR250支持
1 <dependency> 2 <groupId>javax.annotation</groupId> 3 <artifactId>jsr250-api</artifactId> 4 <version>1.0</version> 5 </dependency>View Code
2) 使用@Bean形式的Bean
1 package com.ws.study.prepost; 2 3 public class BeanWayService { 4 5 public void init(){ 6 System.out.println("@Bean-init-method"); 7 } 8 9 public BeanWayService(){ 10 super(); 11 System.out.println("初始化構造函數-BeanWayService"); 12 } 13 14 public void destory(){ 15 System.out.println("@Bean-destroy-method"); 16 } 17 } 18View Code
3) 使用JSR250形式的Bean
1 package com.ws.study.prepost; 2 3 import javax.annotation.PostConstruct; 4 import javax.annotation.PreDestroy; 5 6 public class JSR250WayService { 7 8 // 在構造函數執行完之後執行 9 @PostConstruct 10 public void init(){ 11 System.out.println("jsr250-init-method"); 12 } 13 14 public JSR250WayService(){ 15 super(); 16 System.out.println("初始化構造函數-JSR250WayService"); 17 } 18 19 // 在Bean銷毀之前執行 20 @PreDestroy 21 public void destroy(){ 22 System.out.println("jsr250-destroy-method"); 23 } 24 } 25View Code
4) 配置類
1 package com.ws.study.prepost; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.ComponentScan; 5 import org.springframework.context.annotation.Configuration; 6 7 @Configuration 8 @ComponentScan("com.ws.study.prepost") 9 public class PrePostConfig { 10 11 // initMethod和destroyMethod指定BeanWayService類的init和destroy方法在構造之後、Bean銷毀之前執行 12 @Bean(initMethod = "init", destroyMethod = "destory") 13 BeanWayService beanWayService(){ 14 return new BeanWayService(); 15 } 16 17 @Bean 18 JSR250WayService jsr250WayService(){ 19 return new JSR250WayService(); 20 } 21 } 22View Code
5) 運行類
1 package com.ws.study.prepost; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PrePostConfig.class); 9 10 BeanWayService beanWayService = context.getBean(BeanWayService.class); 11 JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class); 12 13 context.close(); 14 } 15 16 } 17View Code
6) 運行結果
1 五月 31, 2018 10:33:21 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 22:33:21 CST 2018]; root of context hierarchy 3 初始化構造函數-BeanWayService 4 @Bean-init-method 5 初始化構造函數-JSR250WayService 6 jsr250-init-method 7 五月 31, 2018 10:35:58 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 8 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 22:33:21 CST 2018]; root of context hierarchy 9 jsr250-destroy-method 10 @Bean-destroy-method 11View Code
4. Profile
Profile為在不同環境下使用不同的配置提供了支持(開發環境下的配置和生產環境下的配置肯定是不同的,如數據庫配置)。
a. 通過設定Environment的ActiveProfiles來設定當前context需要使用的配置環境。開發中使用@Profile註解類或者方法,達到在不同情況下選擇實例化不同的Bean
b. 通過設定jvm的srping.profiles.active參數來設置配置環境
c. Web項目設置在Servlet的context parameter中
示例:
1) 示例Bean
1 package com.ws.study.profile; 2 3 public class DemoBean { 4 5 private String content; 6 7 8 public DemoBean(String content){ 9 super(); 10 this.content = content; 11 } 12 13 public String getContent() { 14 return content; 15 } 16 17 public void setContent(String content) { 18 this.content = content; 19 } 20 21 } 22View Code
2) Profile配置
1 package com.ws.study.profile; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.context.annotation.Profile; 6 7 @Configuration 8 public class ProfileConfig { 9 10 @Bean 11 // Profile為dev時實例化devDemoBean 12 @Profile("dev") 13 public DemoBean devDemoBean(){ 14 return new DemoBean("from devlopment profile"); 15 } 16 17 @Bean 18 // Profile為prod時實例化prodDemoBean 19 @Profile("prod") 20 public DemoBean proDemoBean(){ 21 return new DemoBean("from production profile"); 22 } 23 }View Code
3) 運行類
1 package com.ws.study.profile; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 9 // 先將活動的Profile設置為prod 10 context.getEnvironment().setActiveProfiles("prod"); 11 // 後置註冊Bean配置類,不然會報Bean未定義的錯誤 12 context.register(ProfileConfig.class); 13 // 刷新容器 14 context.refresh(); 15 16 DemoBean demoBean = context.getBean(DemoBean.class); 17 18 System.out.println(demoBean.getContent()); 19 20 context.close(); 21 } 22 23 } 24View Code
4) 設置為prod的運行結果
1 五月 31, 2018 11:04:32 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 23:04:31 CST 2018]; root of context hierarchy 3 from production profile 4 五月 31, 2018 11:05:05 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 5 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 23:04:31 CST 2018]; root of context hierarchy 6View Code
5) 設置為dev的運行結果
1 五月 31, 2018 11:06:21 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1a71e93: startup date [Thu May 31 23:06:21 CST 2018]; root of context hierarchy 3 from devlopment profile 4 五月 31, 2018 11:06:22 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 5 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1a71e93: startup date [Thu May 31 23:06:21 CST 2018]; root of context hierarchy 6View Code
5. 事件(Application Event)
Spring的事件為Bean和Bean之間的消息通信提供了支持。當一個Bean處理完一個任務之後,希望另一個Bean知道並能做相應的處理。這時我們就需要讓另外一個Bean監聽當前Bean所發送的事件。
Spring事件需要遵循的流程:
a. 自定義事件,繼承ApplicationEvent
b. 定義事件監聽器,實現ApplicationListener
c. 使用容器發布事件
示例:
1) 自定義事件
1 package com.ws.study.event; 2 3 import org.springframework.context.ApplicationEvent; 4 5 public class DemoEvent extends ApplicationEvent{ 6 private static final long serialVersionUID = -7872648566400668161L; 7 8 private String msg; 9 10 public DemoEvent(Object source, String msg) { 11 super(source); 12 this.msg = msg; 13 } 14 15 public String getMsg() { 16 return msg; 17 } 18 19 public void setMsg(String msg) { 20 this.msg = msg; 21 } 22 } 23View Code
2) 事件監聽器
1 package com.ws.study.event; 2 3 import org.springframework.context.ApplicationListener; 4 import org.springframework.stereotype.Component; 5 6 @Component 7 // 實現ApplicationListener接口,並指定監聽的時間類型 8 public class DemoListener implements ApplicationListener<DemoEvent>{ 9 10 // 使用onApplicationEvent方法對消息進行接受處理 11 public void onApplicationEvent(DemoEvent event) { 12 String msg = event.getMsg(); 13 System.out.println("我(bean-demoListener)接受到了bean-demoEvent發布的消息: "+msg); 14 } 15 } 16View Code
3) 事件發布類
1 package com.ws.study.event; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.stereotype.Component; 6 7 @Component 8 public class DemoPublisher { 9 10 // 註入ApplicationContext用來發布事件 11 @Autowired 12 ApplicationContext applicationContext; 13 14 public void publish(String msg){ 15 // 使用ApplicationContext的publishEvent方法來發布 16 applicationContext.publishEvent(new DemoEvent(this, msg)); 17 } 18 } 19View Code
4) 配置類
1 package com.ws.study.event; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.stereotype.Component; 5 6 @Component 7 @ComponentScan("com.ws.study.event") 8 public class EventConfig { 9 } 10View Code
5) 運行類
1 package com.ws.study.event; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 public static void main(String[] args) { 7 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class); 8 DemoPublisher demoPublisher = context.getBean(DemoPublisher.class); 9 demoPublisher.publish("hello application envent"); 10 context.close(); 11 } 12 } 13View Code
6) 運行結果
1 五月 31, 2018 11:23:18 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 23:23:18 CST 2018]; root of context hierarchy 3 我(bean-demoListener)接受到了bean-demoEvent發布的消息: hello application envent 4 五月 31, 2018 11:25:15 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 5 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@dbe50f: startup date [Thu May 31 23:23:18 CST 2018]; root of context hierarchy 6View Code
Spring Boot實戰(2) Spring常用配置