天天看點

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注解是否生效,運作結果如下:

Spring常用配置

OK,接下來我們把第一步建立的類的@Scope注解修改一下,改成下面的樣子:

@Component
@Scope("prototype")
public class ScopeTest {

}      

這個時候再運作,結果如下:

Spring常用配置

本案例下載下傳位址:

本案例GitHub位址

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檔案夾中,如下:

Spring常用配置

t.txt檔案中的内容随意,t.properties檔案中的内容也随意,以我的這兩個檔案為例:

Spring常用配置
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();
    }
}      

運作結果:

Spring常用配置

本案例下載下傳位址

Bean的初始化和銷毀

對于Bean的操作,很多情況下不是簡單的建立,我們還需要做一些必要的初始化操作,同時,用完了,該銷毀的銷毀,該釋放的釋放,這個要怎麼實作呢?

總的來說,有兩種方式:

1.Java配置方式,我們可以使用@Bean的注解中的initMethod和destroyMethod兩個東東,這兩個對應xml配置檔案中的init-method和destroy-method。

2.使用JSR-250中的注解@PostConstruct和@PreDestroy.

我們來看看這兩個案例。

  1. 添加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()");
    }
}      
@Configuration
public class MyConfig {
    @Bean(initMethod = "init",destroyMethod = "destroy")
    BeanWayService beanWayService() {
        return new BeanWayService();
    }
    @Bean
    JSR250WayService jsr250WayService() {
        return new JSR250WayService();
    }
}      

initMethod指定在構造方法執行完成之後執行初始化方法,destroyMethod指定在銷毀之前執行destroy方法。

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();
    }
}      
Spring常用配置

本案例下載下傳位址:

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。

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常用配置

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 {
}      
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();
    }
}      
Spring常用配置

本案例下載下傳位址: