Scope描述的是Spring容器如何创建Bean的示例的。Spring的Scope有以下几种,通过@Scope注解来实现。
使用示例
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service
@Scope("prototype")
public class DemoPrototypeService {
}
spring开发当中涉及调用各种资源的情况,包含普通文件,网址,配置文件,系统环境变量等,可以使用Spring的表达式语言实现资源的注入。
示例代码如下:
pom.xml添加
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.3version>
dependency>
@Service
public class DemoService {
@Value("其他类的属性")
private String another;
public String getAnother() {
return another;
}
public void setAnother(String another) {
this.another = another;
}
}
@Configuration
@ComponentScan("com.xhf.sample4")
//注入配置文件需要指定文件地址
@PropertySource("classpath:com/xhf/sample4/test.properties")
public class ElConfig {
//注入字符串
@Value("I love you")
private String normal;
//注入操作系统属性
@Value("#{systemProperties['os.name']}")
private String osName;
//注入表达式运算结果
@Value("#{T(java.lang.Math).random()*100.0}")
private double randomNumber;
//注入其他bean的属性。demoService应该是bean的默认名称
@Value("#{demoService.another}")
private String fromAnother;
//注入文件资源
@Value("classpath:com/xhf/sample4/test.txt")
private Resource testFile;
//注入网址资源
@Value("http://www.baidu.com")
private Resource testUrl;
//注入配置文件
@Value("${book.name}")
private String bookName;
//Environment可以获取配置文件属性
@Autowired
private Environment environment;
//注入配置文件需要配置这样一个Bean
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigure() {
return new PropertySourcesPlaceholderConfigurer();
}
public void outputResource() {
System.out.println(normal);
System.out.println(osName);
System.out.println(randomNumber);
System.out.println(fromAnother);
try {
System.out.println(IOUtils.toString(testFile.getInputStream()));
System.out.println(IOUtils.toString(testUrl.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(bookName);
System.out.println(environment.getProperty("book.name"));
}
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(ElConfig.class);
ElConfig resourceService = context.getBean(ElConfig.class);
resourceService.outputResource();
context.close();
}
}
输出:
I love you
Linux
37.23290117950025
其他类的属性
hello world
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8>......此处省略
spring boot
spring boot
Spring 可以在Bean 的初始化和销毁的时候做一些操作。提供如下两种方式:
示例:
public class BeanWayService {
public void init() {
System.out.println("@Bean-init-method");
}
public BeanWayService() {
super();
System.out.println("初始化构造函数-BeanWayService");
}
public void destroy() {
System.out.println("@Bean-destroy-method");
}
}
@Component
public class JSR250WayService {
@PostConstruct
public void init() {
System.out.println("JSR250-init-method");
}
public JSR250WayService() {
super();
System.out.println("初始化构造函数-JSR250WayService");
}
@PreDestroy
public void destroy() {
System.out.println("JSR250-destroy-method");
}
}
@Configuration
@ComponentScan("com.xhf.sample5")
public class PrePostConfig {
@Bean(initMethod="init", destroyMethod="destroy") //分别在构造函数执行完之后和销毁之前执行
BeanWayService beanWayService() {
return new BeanWayService();
}
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(PrePostConfig.class);
BeanWayService beanWayService = context.getBean(BeanWayService.class);
JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class);
context.close();
}
}
Profile 为在不同环境下使用不同的配置提供了支持。
Spring的事件需要遵循一下流程
代码示例
自定义事件:
public class DemoEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private String msg;
public DemoEvent(Object source, String msg) {
super(source);
this.setMsg(msg);
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
事件监听
@Component
public class DemoListener implements ApplicationListener<DemoEvent>{
@Override
public void onApplicationEvent(DemoEvent event) {
String msg = event.getMsg();
System.out.println("我接收到了bean-demopublisher发布的消息:"+msg);
}
}
事件发布
@Component
public class DemoPublisher {
@Autowired
ApplicationContext context;
public void publish(String msg) {
context.publishEvent(new DemoEvent(this, msg));
}
}
配置文件
@Configuration
@ComponentScan("com.xhf.sample6")
public class EventConfig {
}
执行程
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context
= new AnnotationConfigApplicationContext(EventConfig.class);
DemoPublisher publisher = context.getBean(DemoPublisher.class);
publisher.publish("hello world");
context.close();
}
}
aware是感知的意思,Spring 提供 Aware 相关的接口出来使用目的就是为了让Bean 可以调用到一些容器所拥有的资源和功能。书中大概是这个意思。
我理解的就是把容器本身的一些功能接口暴露出来,方便我们基于容器做一些功能拓展。相应的这会增强Bean和容器的耦合性。
示例代码如下,实现 BeanNameAware 可以获得 bean name 属性, 实现 ResourceLoaderAware 可以获得容器的资源加载器。
package com.xhf.aware;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
@Service
public class AwareService implements BeanNameAware, ResourceLoaderAware {
private ResourceLoader resourceLoader;
private String name;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setBeanName(String name) {
this.name = name;
}
public void outputResult() {
System.out.println("Bean 的名称为:" + name);
Resource resource = resourceLoader.getResource("classpath:com/xhf/aware/test.txt");
try {
String content = IOUtils.toString(resource.getInputStream());
System.out.println(content);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
配置类
package com.xhf.aware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.xhf.aware")
public class AwareConfig {
}
执行代码
package com.xhf.aware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class);
AwareService awareService = context.getBean(AwareService.class);
awareService.outputResult();
context.close();
}
}
结果如下:
Bean 的名称为:awareService
hello world!!!!!!!!!!!!
Spring 通过任务执行器 TaskExecutor 来实现多线程和并发编程。使用 ThreadPoolTaskExecutor 可实现一个基于线程池的 TaskExecutor 。而实际开发中任务一般是非阻碍的,即异步的。所以要在配置类中通过 @EnableAsync 开启异步任务的支持,并且通过在实际执行的 Bean 的方法中使用 @Async 注解来声明这是一个异步任务。
配置类
package com.xhf.taskexecutor;
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
@ComponentScan("com.xhf.taskexecutor")
public class TaskExecutorConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
异步任务定义:
package com.xhf.taskexecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncTaskService {
@Async
public void executeAsyncTask(Integer i) {
System.out.println("执行异步任务:" + i);
}
@Async
public void executeAsyncTaskPlus(Integer i) {
System.out.println("执行异步任务+1:" + (i+1));
}
}
启动类,执行异步任务:
package com.xhf.taskexecutor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
AsyncTaskService taskService = context.getBean(AsyncTaskService.class);
for (int i = 0; i < 10; i++) {
taskService.executeAsyncTask(i);
taskService.executeAsyncTaskPlus(i);
}
context.close();
}
}
通过在配置类注解 @EnableScheduling 来开启对计划任务的支持,然后在要执行任务的方法上注解@Scheduled,声明这是一个计划任务。
配置类:
package com.xhf.schedule;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@ComponentScan("com.xhf.schedule")
@EnableScheduling
public class TaskSchedulerConfig {
}
定义计划任务:
package com.xhf.schedule;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class ScheduledTaskService {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedRate=5000)
public void reportCurrentTime() {
System.out.println("每隔5秒执行一次,currentTime: "+dateFormat.format(new Date()));
}
@Scheduled(cron="0 28 11 ? * *")
public void fixTimeExecution() {
System.out.println("指定时间执行一次,currentTime: "+dateFormat.format(new Date()));
}
}
启动类,执行计划任务:
package com.xhf.schedule;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskSchedulerConfig.class);
}
}
spring 可以通过 @Conditional 根据满足某一特定条件创建一个特定的 Bean。
以下示例代码,通过实现 Condition 接口,实现 matches 方法来构造判断条件。
package com.xhf.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Windows");
}
}
package com.xhf.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux");
}
}
定义一个接口,后续根据不同的条件来实例化不同的对象。
package com.xhf.conditional;
public interface ListService {
public String showListCmd();
}
package com.xhf.conditional;
public class WindowsListService implements ListService {
@Override
public String showListCmd() {
return "dir";
}
}
package com.xhf.conditional;
public class LinuxListService implements ListService{
@Override
public String showListCmd() {
return "ls";
}
}
配置文件使用 @Conditional 条件来实例化不同的Bean
package com.xhf.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListService windowsListService() {
return new WindowsListService();
}
@Bean
@Conditional(LinuxCondition.class)
public ListService linuxListService() {
return new LinuxListService();
}
}
启动类
package com.xhf.conditional;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
ListService listService = context.getBean(ListService.class);
System.out.println(listService.showListCmd());
context.close();
}
}
元注解就是可以注解到别的注解上的注解,被注解的注解称之为组合注解。
组合注解具有其构成的元注解的功能。
示例,定义一个注解
package com.xhf.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan
public @interface MyConfiguration {
String[] value() default{};
}
定义一个Bean
package com.xhf.annotation;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
public void outPut() {
System.out.println("从组合注解获得Bean ");
}
}
配置类
package com.xhf.annotation;
@MyConfiguration("com.xhf.annotation")
public class DemoConfig {
}
启动类
package com.xhf.annotation;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
DemoService demoService = context.getBean(DemoService.class);
demoService.outPut();
context.close();
}
}
添加测试用的依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>4.1.6.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.11version>
dependency>
定义一个 Bean
package com.xhf.test;
public class TestBean {
private String context;
public TestBean(String context) {
super();
this.context = context;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
}
配置类,不同profile实例化不同的Bean
package com.xhf.test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
public class TestConfig {
@Bean
@Profile("dev")
public TestBean devTestBean() {
return new TestBean(" form dev profile ");
}
@Bean
@Profile("prod")
public TestBean prodTestBean() {
return new TestBean(" form prod profile ");
}
}
测试用例,
@RunWith(SpringJUnit4ClassRunner.class) 它提供了 Spring Testcontext Framework的功能。
@ContextConfiguration(classes={TestConfig.class}) 配置配置文件。
@ActiveProfiles(“prod”) 去定活动的profile
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.xhf.test.TestBean;
import com.xhf.test.TestConfig;
import junit.framework.Assert;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={TestConfig.class})
@ActiveProfiles("prod")
public class DemoBeanIntegrationTests {
@Autowired
private TestBean testBean;
@Test
public void prodBean() {
String expect = " form prod profile ";
String actual = testBean.getContext();
Assert.assertEquals(expect, actual);
}
}