1,点睛
spring的依赖注入的最大亮点就是你所有的Bean对Spring容器的存在是没有意识的,即你可以将你的容器替换成别的容器,如Google Guice,这时Bean之间的耦合度很低。
但是在实际项目中,你不可避免的要用到Spring容器本身的功能资源,这时你的Bean必须意识到Spring容器的的存在,才能调用Spring所提供的资源,这就是所谓的Spring Aware。其实Spring Aware本来就是Spring设计用来框架内容使用的,若使用了Spring Aware,你的Bean将会和Spring框架耦合。
Spring提供的Aware接口如下:
BeanNameAware:获得容器中的bean名称
BeanFactoryAware:获得当前bean factory,这样就可以调用容器的服务
ApplicationContextAwate*:当前application context,这样可以调用容器的服务
MessageSourceAware:获得message source,这样可以获得文本信息
ApplicationEventPublisherAware:应用时间发布器,可以发布事件
ResourceLoaderAware:获得资源加载器,可以获得外部资源文件
Spring Aware的目的是为了让Bean获得Spring容器的服务。因为ApplicationContext接口集成了MessageSource接口,ApplicationEventPublisher接口和ResourceLoader接口,所以Bean继承ApplicationContextAware可以获得Spring容器的所有服务,但原则上我们还是用到什么接口,就实现什么接口。
示例如下:
在jack.ch3.aware包下新建一个test.txt,内容随意,给下面的外部资源加载使用。
Spring Aware演示Bean:
package jack.ch3.aware; 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; /** * Created by jack on 2017/7/11. */ //实现BeanNameAware,ResourceLoaderAware接口,获得Bean名称和资源加载的服务 @Service public class AwareService implements BeanNameAware,ResourceLoaderAware{ private String beanName; private ResourceLoader loader; //实现BeanNameAware需重写setBeanName @Override public void setBeanName(String name) { this.beanName = name; } //实现ResourceLoaderAware需重写setResourceLoader @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.loader = resourceLoader; } public void outputResult(){ System.out.println("Bean的名称为:"+beanName); Resource resource = loader.getResource("classpath:jack/ch3/aware/test.txt"); try { System.out.println("ResourceLoader加载文件内容为: "+ IOUtils.toString(resource.getInputStream())); }catch (Exception e){ e.printStackTrace(); } } }
配置类:
package jack.ch3.aware; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * Created by jack on 2017/7/11. */ @Configuration @ComponentScan("jack.ch3.aware") public class AwareConfig { }
测试代码如下:
package jack.ch3.aware; import jack.ch2.event.DemoPublisher; import jack.ch2.event.EventConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Created by jack on 2017/7/11. */ public class MainTest9 { public static void main(String [] args){ //AnnotationConfigApplicationContext作为spring容器,接受一个配置类作为参数 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class); AwareService awareService = context.getBean(AwareService.class); awareService.outputResult(); context.close(); } }
运行测试程序,结果如下:
下面是示例:
配置类:
package jack.ch3.taskexecutor; 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; import java.util.concurrent.Executor; /** * Created by jack on 2017/7/15. */ @Configuration @ComponentScan("jack.ch3.taskexecutor") @EnableAsync//利用@EnableAsync注解开启异步任务支持 /** * 配置类实现AsyncConfigurer接口,并重写getAsyncExecutor方法,并返回一个ThreadPoolTaskExecutor,这样我们就获得一个基于 * 线程池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 jack.ch3.taskexecutor; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; /** * Created by jack on 2017/7/15. */ @Service public class AsyncTaskService { //通过@Async注解表明该方法是一个异步方法,如果注解在类级别上,则表明该类所有的方法都是异步方法, //而这里的方法自动被注入使用ThreadPoolTaskExecutor作为TaskExecutor @Async public void executeAysncTask(Integer i){ System.out.println("执行异步任务:"+i); } @Async public void executeAsyncTaskPlus(Integer i){ System.out.println("执行异步任务+1:"+(i+1)); } }
测试代码如下:
package jack.ch3.taskexecutor; import jack.ch2.event.DemoPublisher; import jack.ch2.event.EventConfig; import jack.ch3.aware.AwareService; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.scheduling.annotation.AsyncConfigurer; /** * Created by jack on 2017/7/15. */ public class MainTest9 { public static void main(String [] args){ //AnnotationConfigApplicationContext作为spring容器,接受一个配置类作为参数 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class); AsyncTaskService asyncTaskService = context.getBean(AsyncTaskService.class); for (int i=0;i<10;i++){ asyncTaskService.executeAysncTask(i); asyncTaskService.executeAsyncTaskPlus(i); } context.close(); } }
运行程序,结果是并发的而不是顺序执行的,如下:
spring通过@Scheduled支持多种类型的计划任务,保护cron,fixDelay,fixRate等。
示例如下:
计划任务执行类:
package jack.ch3.taskscheduler; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.SimpleFormatter; /** * Created by jack on 2017/7/15. */ @Service public class ScheduledTaskService { private static final SimpleDateFormat dateFormate = new SimpleDateFormat("HH:mm:ss"); //通过@Scheduled声明该方法是计划任务,使用fixedRate属性每隔固定时间执行 @Scheduled(fixedRate = 5000) public void reportCurrentTime(){ System.out.println("每隔五秒执行一次:"+dateFormate.format(new Date())); } //使用cron属性可按照指定时间执行,本例指定在11点25分执行;cron是UNIX和类UNIX(Linux)系统下的定时任务 @Scheduled(cron = "0 25 11 ? * *") public void fixTimeExecutor(){ System.out.println("在指定时间:"+dateFormate.format(new Date())+" 执行"); } }
计划任务配置类:
package jack.ch3.taskscheduler; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; /** * Created by jack on 2017/7/15. */ @Configuration @ComponentScan("jack.ch3.taskscheduler") @EnableScheduling //通过@EnableScheduling 注解开启对计划任务的支持 public class TaskSchedulerConfig { }
测试代码:
package jack.ch3.taskscheduler; import jack.ch3.taskexecutor.AsyncTaskService; import jack.ch3.taskexecutor.TaskExecutorConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Created by jack on 2017/7/15. */ public class MainTest10 { public static void main(String [] args){ //AnnotationConfigApplicationContext作为spring容器,接受一个配置类作为参数 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskSchedulerConfig.class); //context.close();计划任务这里不能关闭,需要一直在后台运行 } }
运行测试程序,结果如下:
通过输出结果可以看出,一个是每隔5秒执行的,一个是定时执行的。
@Conditional根据满足某一个特定条件创建一个特定的Bean。比方说,当某一个jar包在一个类路径下的时候,自动配置一个;或者只有某个bean被创建才会创建另外一个bean。总的来说,就是根据特定条件来控制bean的创建行为,这样我们就可以利用这个特性进行一些自动化的配置。
在spring boot中将会大量应用到条件注解。
下面的示例将以不同的操作系统作为条件,我们将通过实行Condition接口,并重写matches方法来构造判断条件。若在Window系统下运行程序,则输出列表命令dir;若在Linux系统下运行程序,则输出列表命令ls。
示例如下:
判定Windows的条件:
package jack.ch3.conditional; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; /** * Created by jack on 2017/7/15. */ //判断Window的条件 public class WindowsConditional implements Condition{ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return conditionContext.getEnvironment().getProperty("os.name").contains("Windows"); } }
判定Linux的条件:
package jack.ch3.conditional; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; /** * Created by jack on 2017/7/15. */ //判断Linux的条件 public class LinuxConditional implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { return conditionContext.getEnvironment().getProperty("os.name").contains("Linux"); } }
下面是一个接口:
package jack.ch3.conditional; /** * Created by jack on 2017/7/15. * 接口 */ public interface ListServer { public String showListCmd(); }
Windows下所要创建的Bean的类:
package jack.ch3.conditional; /** * Created by jack on 2017/7/15. */ //Windows下所创建的Bean的类 public class WindowsListService implements ListServer { @Override public String showListCmd() { return "dir"; } }
Linux下所要创建的Bean类:
package jack.ch3.conditional; /** * Created by jack on 2017/7/15. */ //Linux下所要创建的Bean类 public class LinuxListService implements ListServer { @Override public String showListCmd() { return "ls"; } }
配置类:
package jack.ch3.conditional; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; /** * Created by jack on 2017/7/15. */ @Configuration public class ConditionConfig { /** * 通过@Conditional注解,符合Windows条件则实例化windowsListService * @return */ @Bean @Conditional(WindowsConditional.class) public ListServer windowsListService(){ return new WindowsListService(); } /** * 通过@Conditional注解,符合Linux条件则实例化linuxListService * @return */ @Bean @Conditional(LinuxConditional.class) public ListServer linuxListService(){ return new LinuxListService(); } }
测试代码如下:
package jack.ch3.conditional; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; /** * Created by jack on 2017/7/15. */ @Configuration public class ConditionConfig { /** * 通过@Conditional注解,符合Windows条件则实例化windowsListService * @return */ @Bean @Conditional(WindowsConditional.class) public ListServer windowsListService(){ return new WindowsListService(); } /** * 通过@Conditional注解,符合Linux条件则实例化linuxListService * @return */ @Bean @Conditional(LinuxConditional.class) public ListServer linuxListService(){ return new LinuxListService(); } }
运行结果如下:
