Spring常用配置
上篇文章我們簡單介紹了Spring的基本配置,算是一個簡單的入門,這篇文章我們再一起來看看Spring在使用的過程中一些其他的常見配置。
Bean的Scope
Spring中的Scope註解主要是為了解決Bean的例項問題,就是Bean在不同的場合下到底該有幾個例項,是單例模式還是其他模式?一般來說,Spring的Scope有如下幾種:
1.Singleton:表示該Bean是單例模式,在Spring容器中共享一個Bean的例項
2.Prototype:每次呼叫都會新建立一個Bean的例項
3.Request:這個是使用在Web中,給每一個http request新建一個Bean例項
4.Session:這個同樣是使用在Web中,表示給每一個http session新建一個Bean例項
OK,接下來通過一個簡單的案例來看看@Scope註解要怎麼使用:
1.編寫一個Bean
Component
@Scope("singleton")
public class ScopeTest {
}
小夥伴們注意,這裡我使用了@Scope("singleton")
註解,這個註解表示該類是一個單例模式,如果想使用prototype模式,將singleton
改為prototype
即可。
2.配置類
@Configuration
@ComponentScan("org.sang")
public class MyConfig {
}
這個配置類很簡單,沒什麼好說的,有疑問請檢視上篇博文。
3.使用
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
ScopeTest bean1 = context.getBean(ScopeTest.class);
ScopeTest bean2 = context.getBean(ScopeTest.class);
System.out .println(bean1.equals(bean2));
context.close();
}
}
這裡的我們直接獲取兩個ScopeTest類的例項,然後比較這兩個是否是同一個就可以知道@Scope註解是否生效,執行結果如下:
OK,接下來我們把第一步建立的類的@Scope註解修改一下,改成下面的樣子:
@Component
@Scope("prototype")
public class ScopeTest {
}
這個時候再執行,結果如下:
本案例下載地址:
Spring EL和資源呼叫
Spring 中的EL 表示式有點類似於JSP中的EL表示式,它支援在xml檔案和註解中使用表示式。另一方面,JavaEE開發中我們可能經常要注入不同型別的檔案,這些檔案在注入成功之後我們要通過EL來提取其中的值,OK,那我們來看一個簡單的例項。
1.新增commons-io工具類,簡化file操作
因為本案例後面會涉及到一點IO操作,使用這個工具類可以幫助我們簡化操作
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
2.新增t.txt檔案、t.properties檔案
新增兩個檔案來演示檔案的注入,我使用IntelliJ IDEA來做開發的,我們這兩個檔案放在resources資料夾中,如下:
t.txt檔案中的內容隨意,t.properties檔案中的內容也隨意,以我的這兩個檔案為例:
3.編寫需要被注入的Bean
@Service
public class DemoService1 {
//注入普通字串
@Value("老王")
private String author;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
這個很簡單,不多說。
4.編寫配置類
@Configuration
@ComponentScan("org.sang")
@PropertySource(value = "t.properties",encoding = "UTF-8")
public class ELConfig {
@Value("I Love You!")
private String normal;
@Value("#{systemProperties['os.name']}")
private String osName;
@Value("#{systemEnvironment['os.arch']}")
private String osArch;
@Value("#{T(java.lang.Math).random()*100}")
private double randomNumber;
@Value("#{demoService1.author}")
private String author;
@Value("t.txt")
private Resource testFile;
@Value("http://www.baidu.com")
private Resource testUrl;
@Value("${sang.username}")
private String su;
@Value("${sang.password}")
private String sp;
@Value("${sang.nickname}")
private String sn;
@Autowired
private Environment environment;
public void output() {
try {
System.out.println(normal);
System.out.println(osName);
System.out.println(osArch);
System.out.println(randomNumber);
System.out.println(author);
System.out.println(IOUtils.toString(testFile.getInputStream(),"UTF-8"));
//訪問網址
System.out.println(IOUtils.toString(testUrl.getInputStream(),"UTF-8"));
//獲取網址
System.out.println("testUrl.getURL():"+testUrl.getURL());
System.out.println(su);
System.out.println(sp);
System.out.println(sn);
System.out.println(environment.getProperty("sang.nickname"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
OK ,小夥伴們看到,我們首先需要在類上使用@PropertySource來指定檔案地址,將t.properties注入。在屬性上我們可以直接使用@Value來完成注入,可以注入普通的字串,也可以執行一行Java程式碼,可以將某一個類的屬性值注入,也可以注入一個檔案,等,不贅述。我們注入的t.properties除了通過${aaa.bbb}獲取之外,也可以從Environment中獲得。
當然,我們還需要一個配置類,如下:
@Configuration
@ComponentScan("org.sang")
public class MyConfig {
}
5.執行
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
ELConfig bean = context.getBean(ELConfig.class);
bean.output();
context.close();
}
}
執行結果:
Bean的初始化和銷燬
對於Bean的操作,很多情況下不是簡單的建立,我們還需要做一些必要的初始化操作,同時,用完了,該銷燬的銷燬,該釋放的釋放,這個要怎麼實現呢?
總的來說,有兩種方式:
1.Java配置方式,我們可以使用@Bean的註解中的initMethod和destroyMethod兩個東東,這兩個對應xml配置檔案中的init-method和destroy-method。
2.使用JSR-250中的註解@PostConstruct和@PreDestroy.
我們來看看這兩個案例。
- 新增JSR-250支援
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
2.使用Java配置的方式操作Bean
public class BeanWayService {
public void init() {
System.out.println("BeanWayService-init()");
}
public BeanWayService() {
System.out.println("BeanWayService-構造方法");
}
public void destroy() {
System.out.println("BeanWayService-destroy()");
}
}
3.使用JSR-250的方式操作Bean
public class JSR250WayService {
@PostConstruct//構造方法執行之後執行
public void init() {
System.out.println("JSR250WayService-init()");
}
public JSR250WayService() {
System.out.println("JSR250WayService-構造方法");
}
@PreDestroy//銷燬之前執行
public void destroy() {
System.out.println("JSR250WayService-destroy()");
}
}
4.編寫配置類
@Configuration
public class MyConfig {
@Bean(initMethod = "init",destroyMethod = "destroy")
BeanWayService beanWayService() {
return new BeanWayService();
}
@Bean
JSR250WayService jsr250WayService() {
return new JSR250WayService();
}
}
initMethod指定在構造方法執行完成之後執行初始化方法,destroyMethod指定在銷燬之前執行destroy方法。
5.執行
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
BeanWayService beanWayService = context.getBean(BeanWayService.class);
JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class);
context.close();
}
}
執行結果:
Profile問題
在開發中我們一個常見的需求是資料庫的連線配置,在開發時資料庫是一種配置方式,專案釋出的時候資料庫又是另外一種配置方式。對於這個問題,我們可以採用@Profile註解來簡化在兩種不同的配置中切換。OK,接下來我們來看看@Profile註解的使用。
1.建立示例Bean
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配置
@Configuration
public class ProfileConfig {
@Bean
@Profile("dev")
public DemoBean devDemoBean() {
return new DemoBean("dev");
}
@Bean
@Profile("prod")
public DemoBean prodDemoBean() {
return new DemoBean("prod");
}
}
當Profile為dev時使用devDemoBean來例項化DemoBean,當Profile為prod時,使用prodDemoBean來例項化DemoBean。
3.使用
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("prod");
context.register(ProfileConfig.class);
context.refresh();
DemoBean bean = context.getBean(DemoBean.class);
System.out.println(bean.getContent());
context.close();
}
}
這裡還是先獲取Spring容器,這不過在獲取容器時先不傳入配置檔案,待我們先將活動的Profile置為prod之後,再設定配置檔案,設定成功之後,一定要重新整理容器。
執行結果:
本案例下載地址:
Spring中的事件傳遞
有的時候,我們可能希望當一個Bean完成某一項操作的時候,能夠通知到其他的Bean,其他Bean收到訊息後做出相應的處理。Spring對此也提供了相應的支援,在Spring框架內我們可以很好的完成事件的傳送與接收。
1.定義訊息載體
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;
}
}
2.定義事件監聽器
@Component
public class DemoListener implements ApplicationListener<DemoEvent> {
public void onApplicationEvent(DemoEvent demoEvent) {
System.out.println("我收到DemoEvent的事件了:"+demoEvent.getMsg());
}
}
3.定義事件釋出者
@Component
public class DemoPublish{
@Autowired
ApplicationContext applicationContext;
public void publish(String msg) {
applicationContext.publishEvent(new DemoEvent(this,msg));
}
}
4.配置類
@Configuration
@ComponentScan("org.sang")
public class MyConfig {
}
5.執行
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
DemoPublish demoPublish = context.getBean(DemoPublish.class);
demoPublish.publish("Hello sang !");
context.close();
}
}
執行結果:
本案例下載地址:
OK,以上就是Spring中一些常見的配置。
參考資料:
《JavaEE開發的顛覆者 Spring Boot實戰》第二章