1. 程式人生 > >Spring常用配置

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.

我們來看看這兩個案例。

  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()");
    }
}

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實戰》第二章