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注解是否生效,运行结果如下:
![](http://ww4.sinaimg.cn/mw690/6b239626gw1fapg2lml4wj20cd03cdgw.jpg)  
OK,接下来我们把第一步创建的类的@Scope注解修改一下,改成下面的样子:

@Component @Scope(“prototype”) public class ScopeTest {

}

这个时候再运行,结果如下:
![](http://ww3.sinaimg.cn/mw690/6b239626gw1fapg6do0wgj20c404bdh5.jpg)  

本案例下载地址:

[本案例GitHub地址](https://github.com/lenve/JavaEETest/tree/master/Test7-Scope)
###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文件夹中,如下:
![](http://ww1.sinaimg.cn/mw690/6b239626gw1fapgmi8ji9j2077099wf4.jpg)  
t.txt文件中的内容随意,t.properties文件中的内容也随意,以我的这两个文件为例:
![](http://ww2.sinaimg.cn/mw690/6b239626gw1fapgpp601dj20f1055q3q.jpg)  

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

运行结果:
![](http://ww1.sinaimg.cn/mw690/6b239626gw1faph16eorjj20q20bjtcz.jpg)

本案例下载地址
[本案例GitHub地址](https://github.com/lenve/JavaEETest/tree/master/Test8-EL)

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

运行结果:
![](http://ww2.sinaimg.cn/mw690/6b239626gw1faphi7lu25j20kh0600vp.jpg)  

本案例下载地址:
[本案例GitHub地址](https://github.com/lenve/JavaEETest/tree/master/Test9-BeanLiftCycle)
###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之后,再设置配置文件,设置成功之后,一定要刷新容器。
运行结果:
![](http://ww4.sinaimg.cn/mw690/6b239626gw1faq2o0lkiaj20gf043abu.jpg) 
本案例下载地址:

[本案例GitHub地址](https://github.com/lenve/JavaEETest/tree/master/Test10-Profile)
###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{ 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(); } } ``` 运行结果:

本案例下载地址:

本案例GitHub地址

OK,以上就是Spring中一些常见的配置。

参考资料: 《JavaEE开发的颠覆者 Spring Boot实战》第二章

原文发布于微信公众号 - 玩转JavaEE(gh_d1ca11234a30)

原文发表时间:2017-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

Python日志输出——logging模块

http://blog.csdn.net/chosen0ne/article/details/7319306

16710
来自专栏代码拾遗

深入理解Spring MVC

使用Spring Boot和web,thymeleaf的starter来设置初始工程。xml配置如下:

12120
来自专栏Jerry的SAP技术分享

MongoDB最简单的入门教程之五-通过Restful API访问MongoDB

通过前面四篇的学习,我们已经在本地安装了一个MongoDB数据库,并且通过一个简单的Spring boot应用的单元测试,插入了几条记录到MongoDB中,并通...

16510
来自专栏开发与安全

linux网络编程之System V 消息队列(一):消息队列内核结构和msgget、msgctl 函数

一、消息队列 1、消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 2、每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值 ...

23400
来自专栏青青天空树

spring基础(2:最小化XML配置)

  byType在出现多个匹配项时不会自动选择一个然是报错,为避免报错,有两种办法:1.使用<bean>元素的primary属性,设置为首选Bean,但所有be...

11020
来自专栏帅小子的日常

使用redis做缓存

82470
来自专栏阿杜的世界

Java Web技术经验总结(八)

使用XML文件中的mvc:annoation-driven元素也可以,具体代码如下:

11030
来自专栏IT 指南者专栏

Spring框架系列(二)之Bean的注解管理

微信公众号:compassblog 欢迎关注、转发,互相学习,共同进步! 有任何问题,请后台留言联系! 1、Spring中的两种容器 在系列(一)中我们已经知道...

34860
来自专栏C/C++基础

CMake简介及使用实例

CMake是一个跨平台的建构系统的工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的构建文档makefile或者project文件,描...

20020
来自专栏猿天地

知识点-Spring Boot 统一异常处理汇总

上面讲的是做页面开发的时候遇到的问题,还有一种情况就是用来开发Rest接口,当错误的时候我们希望返回给用户的是我们接口的标准格式,不是返回一段html代码。

15620

扫码关注云+社区

领取腾讯云代金券