第3章 Spring 高级话题
2018-12-05 本文已影响0人
意大利大炮
Spring Aware
- Spring的依赖注入最大的亮点就是所有的Bean对Spring容器的存在是没有意识的,所以Bean之间的耦合度很低
- 但是在项目中,我们可能会需要用到Spring容器本身的功能资源,这就需要我们的Bean能够意识到Spring的存在,这就是Spring Aware(Spring可意识到)
- 注:如果使用了Spring Aware,我们的Bean将于Spring框架耦合
Spring提供的Aware接口如表格所示:
接口 | 用途/说明 |
---|---|
BeanNameAware | 可以在Bean中得到它在IOC容器中的Bean的实例的名字 |
BeanFactoryAware | 可以在Bean中得到Bean所在的IOC容器,从而直接在Bean中使用IOC容器的服务 |
ApplicationContextAware | 可以在Bean中得到Bean所在的应用上下文,从而直接在Bean中使用上下文的服务 |
MessageSourceAware | 在Bean中可以得到消息源 |
ApplicationEventPublisherAware | 在bean中可以得到应用上下文的事件发布器,从而可以在Bean中发布应用上下文的事件 |
ResourceLoaderAware | 在Bean中可以得到ResourceLoader,从而在bean中使用ResourceLoader加载外部对应的Resource资源 |
- 使用Aware接口时,首先要创建一个继承了Aware接口的bean,并实现其方法
例:
@Service
public class AwareService implements ResourceLoaderAware{
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.loader = resourceLoader;
}
}
多线程
- Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程
- 使用ThreadPoolTaskExecutor可实现一个基于县城池的TaskExecutor
下面是一个例子
- 首先实现一个实现了AsyncConfigurer 接口的配置类,并重写getAsyncExecutor()方法
@Configuration
@ComponentScan("com.example.demo")
@EnableAsync // 使用注解开启异步任务支持
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;
}
}
- 创建异步service类,通过@Async注解表明异步方法
@Service
public class AsyncTaskService {
@Async
public void executeAsyncTask(Integer i) {
System.out.println("执行异步任务1:" + i);
}
@Async
public void executeAsyncTaskPlus(Integer i) {
System.out.println("执行异步任务2:" + i);
}
}
- 运行
public class Main {
public static void main(String args[]) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
AsyncTaskService asyncTaskService = context.getBean(AsyncTaskService.class);
// 循环调用
for (int i = 0; i < 10; i++) {
asyncTaskService.executeAsyncTask(i);
asyncTaskService.executeAsyncTaskPlus(i);
}
// 关闭
context.close();
}
}
计划任务(定时任务)
- 通过@@EnableScheduling 注解支持多种类型的计划任务,包含cron、fixDelay、fixRate等
@Configuration
@ComponentScan("com.example.demo.scheduled_test.service")
@EnableScheduling // 开启定时任务的支持
public class TaskSchedulerConfig {
}
- 通过@Scheduled生命计划任务方法,使用fixedRate属性每隔指定时间执行,使用cron属性可按照指定时间执行
@Service
public class ScheduledTaskService {
@Scheduled(fixedDelay = 5000)
public void reportCurrentTime() {
System.out.println("每个五秒钟执行一次 ");
}
/**
* 在每天的11点28分执行
*/
@Scheduled(cron = "0 28 11 ? * *")
public void fixTimeExecution() {
System.out.println("在指定时间执行");
}
}
- 运行
public class Main {
public static void main(String args[]) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(TaskSchedulerConfig.class);
}
}
条件注解@Conditional
- 基于条件创建Bean
- 满足某个条件创建一个特定的Bean
例子:windows环境下生成windowsBean,linux下生成linuxBean - 创建条件定义
windows定义
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Windows");
}
}
linux定义
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Linux");
}
}
- 不同系统下面的Bean
接口
public interface ListService {
String showListCmd();
}
windows下要创建的Bean
public class WindowsListService implements ListService {
@Override
public String showListCmd() {
return "dir";
}
}
Linux下要创建的Bean
public class LinuxListService implements ListService {
@Override
public String showListCmd() {
return "ls";
}
}
- 配置类
@Configuration
public class ConditionConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListService windows() {
return new WindowsListService();
}
@Bean
@Conditional(LinuxCondition.class)
public ListService linux() {
return new LinuxListService();
}
}
- 运行
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());
}
}
组合注解与元注解
- 所谓元注解,就是可以注解到别的注解上的注解,而被注解的注解成为组合注解
- 组合注解具备所组成的元注解的功能
- Spring中有很多元注解和组合注解
- 我们也可以自己实现自定义组合注解
例:组合@Configuration和@ComponentScan注解\ - 创建组合注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan
public @interface WiselyConfiguration {
String[] value() default {};
}
- 创建用来演示的bean
@Service
public class DemoService {
public void outPutResult() {
System.out.println("从组合注解处照样获得的bean");
}
}
- 创建配置类
@WiselyConfiguration("com.example.demo.simple_conditional.service")
public class DemoConfig {
}
- 运行
public class Main {
public static void main(String args[]) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
DemoService demoService = context.getBean(DemoService.class);
demoService.outPutResult();
}
}
@Enable* 注解的工作原理
- spring通过@Enable*开启一些功能的支持,但他的底层源码其实通过@Import注解来导入配置类的,也就说这些自动开启的实现其实是导入了一些自动配置的Beans
导入配置的方式一般有三种:
- 直接导入配置类
- 依据条件选择配置类
- 动态注册Bean
测试
- 测试是开发工作必不可少的一部分
- Spring通过Spring TestContext Framework对集成测试提供顶级支持。它不依赖于特定的测试框架,既可以使用Junit,也可以使用TestNG
例: - 配置maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>apring-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
- 创建Bean
public class TestBean {
private String content;
public TestBean(String content) {
super();
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
- 创建配置类
@Configuration
public class TestConfig {
@Bean
@Profile("dev")
public TestBean devTestBean() {
return new TestBean("dev");
}
@Bean
@Profile("prod")
public TestBean prodTestBean() {
return new TestBean("prod");
}
}
- 运行
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestBean.class})
@ActiveProfiles("prod")
public class Main {
@Autowired
private TestBean testBean;
@Test
public void test() {
System.out.println(testBean.getContent());
}
}