Spring高级话题
三.Spring高级话题
1.spring aware
Spring的依赖注入的最大亮点就是bean对spring容器的存在是没有意识的。
若你想用spring容器本身的资源,bean就要意识到spring容器的存在。
Spring提供的aware接口:
(1) beanNameAware : 获得到容器中bean名称。
(2) beanFactoryAware :获得当前bean factory,这样可以调用容器的服务。
(3) applicationContextAware:当前的application context.这样可以调用容器的服务。
(4) messageSourceAware :获得message source,这样可以获得文本信息。
(5) ApplicationEventPublisherAware:应用事件发布器,可以发布事件。
(6) ResourceLoaderAware:获得资源加载器,可以获得外部资源文件。
Spring aware 的目的是为了让bean获得spring容器的服务,因为applicationContext接口集成了messageSource接口、applicationEventPublisher接口和ResourceLoader接口。
所以bean继承applicationContextAware可以获取到spring容器的所有服务。
代码示例:
@Service
public class AwareService implements BeanNameAware,ResourceLoaderAware{
private String beanName;
private ResourceLoader loader;
@Override
public void setResourceLoader(ResourceLoader paramResourceLoader) {
// TODO Auto-generated method stub
this.loader = paramResourceLoader;
}
@Override
public void setBeanName(String msg) {
// TODO Auto-generated method stub
this.beanName = msg;
}
public void outputResult(){
System.out.println("bean的名称为:"+beanName);
Resource resource = loader.getResource("classpath:cn/cw/study/springaware/test.txt");
try {
String string = IOUtils.toString(resource.getInputStream());
System.out.println("接收的内容是:"+string);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
---------------------------------------------------------------------
@Configuration
@ComponentScan("cn.cw.study.springaware")
public class AwareConfig {
}
---------------------------------------------------------------------
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class);
AwareService bean = context.getBean(AwareService.class);
bean.outputResult();
context.close();
}
}2.多线程
Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步任务的支持,并通过在实际执行的bean的方法中使用@Async注解来声明其是一个异步任务。
@Async注解:
①如果注解在方法级别,则表明该方法是异步方法,
②如果注解在类级别,则表明类所有的方法都是异步方法,
@EnableAsync注解:
开启对异步任务的支持。
代码示例:
@Configuration
@ComponentScan("cn.cw.study.ThreadPool")
@EnableAsync //开启异步任务支持
public class TaskExecutorConfig implements AsyncConfigurer{
@Override
public Executor getAsyncExecutor() {
// TODO Auto-generated method stub
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);//核心线程数
executor.setMaxPoolSize(10);//最大线程数
executor.setQueueCapacity(25);//队列最大长度
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// TODO Auto-generated method stub
return null;
}
}
@Service
public class AsyncTaskService {
//无注解表明是同步方法,顺序执行
public void executeTask(int i){
System.out.println("执行同步任务:"+i);
}
//注解表明该方法是异步方法,如果注解在类级别,则表明该类所有的方法都是异步方法,而这里的方法自动被注解使用ThreadPoolTaskExecutor作为TaskExecutor
@Async
public void executeTaskTest(int i){
System.out.println("执行异步任务+1:"+(i+1));
}
}
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
AsyncTaskService bean = context.getBean(AsyncTaskService.class);
for(int i=0;i<10;i++){
bean.executeTask(i);
bean.executeTaskTest(i);
}
context.close();
}
}3.计划任务
从spring 3.1开始,计划任务在spring中实现变得异常简单,首先通过在配置类注解@EnableScheduling来开启对计划任务的支持,然后再要执行计划任务的方法上注解@Sheduled,声明这是一个计划任务。
Spring 通过@Scheduled支持多种类型的计划任务,包含cron、fixDelay、fixRate等。
代码示例:
@Service
public class ScheduleTaskService {
private SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
@Scheduled(fixedRate=1000)
public void reportFixedRate(){
System.out.println("rate:"+format.format(new Date()));
}
@Scheduled(fixedDelay=4000)
public void reportDelay(){
System.out.println("delay:"+format.format(new Date()));
}
@Scheduled(cron="0 29 11 * * *")
public void reportCron(){
System.out.println("rate:"+format.format(new Date()));
}
}
@Configuration
@ComponentScan("cn.cw.study.schedule")
@EnableScheduling //开启对计划任务的支持
public class TaskConfig {
}
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskConfig.class);
// context.close();不能关闭context,关闭后 将不会执行定时任务
}
}4.条件注解@Conditional
Spring 通过活动创建一个特定bean。
spring4提供了一个更通用的基于条件的bean创建。使用注解@Conditional。
@Conditional根据满足某一个特定条件创建一个特定bean。
比如,当某一个jar包在一个类路径下的时候,会自动配置一个或者多个bean;或者只有某个bean被创建才会创建另一个bean;总的来说,就是根据特定条件来控制bean的创建行为,这样我们可以利用这个特性进行一些自动配置。
下面例子代码思想:
通过实现condition接口,并重写matches方法来构造条件。
若在windows系统下运行程序,则输出列表命令为dir;若在linux系统下运行程序,则输出列表命令ls
代码示例:
public class WindowsCondition implements Condition{
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata data) {
System.out.println(context.getEnvironment().getProperty("os.name"));
// TODO Auto-generated method stub
return context.getEnvironment().getProperty("os.name").contains("Windows");
}
}
public class LinuxCondition implements Condition{
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata data) {
// TODO Auto-generated method stub
return context.getEnvironment().getProperty("os.name").contains("Linux");
}
}
public interface ListServer {
public String showListCmd();
}
public class WindowsListService implements ListServer{
@Override
public String showListCmd() {
// TODO Auto-generated method stub
return "dir";
}
}
public class LinuxListService implements ListServer{
@Override
public String showListCmd() {
// TODO Auto-generated method stub
return "ls";
}
}
@Configuration
public class ConditionConfig {
@Bean
@Conditional(WindowsCondition.class)
public ListServer windowsService(){
return new WindowsListService();
}
@Bean
@Conditional(LinuxCondition.class)
public ListServer linuxService(){
return new LinuxListService();
}
}
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);
ListServer listServer = context.getBean(ListServer.class);
System.out.println(context.getEnvironment().getProperty("os.name")+"系统下的列表命名为:"+listServer.showListCmd());
}
}5.组合注解与元注解
从spring2开始,为了响应jdk1.5推出的注解功能,spring开始大量加入注解来替代xml配置,spring的注解主要用来配置和注入bean,以及aop相关配置(@Transactional).
随着注解的大量使用,尤其相同的多个注解用到各个类或方法中,会相当繁琐。
所谓元注解其实就是可以注解到别的注解上的注解,被注解的注解称之为组合注解,组合注解具备注解其上的元注解的功能。
Spring的很多注解都可以作为元注解,而且spring 本身已经有很多组合注解,如@Configuration就是一个组合@Component注解,表明这个类其实也是一个bean.
代码示例:
将@Configuration和@ComponentScan注解组成一个组合注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan
public @interface WiselyConfiguration {
String[] value() default{};//覆盖value参数
}
@Service
public class DemoService {
public void outputResult(){
System.out.println("组合注解可以获得bean");
}
}
@WiselyConfiguration("cn.cw.study.compositeAnnotation")
public class DemoConfig {
}
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
DemoService bean = context.getBean(DemoService.class);
bean.outputResult();
context.close();
}
}6.@Enable* 注解的工作原理
(1).@EnableAspectJAutoProxy 开启对AspectJ 自动代理的支持。
(2).@EnableAsync 开启异步方法的支持。
(3).@EnableScheduling 开启计划任务的支持。
(4).@EnableWebMvc 开启web mvc的配置支持。
(5).@EnableConfigurationProperties 开启对@ConfigurationProperties注解配置的bean的支持
(6).@EnableJpaRepositories 开启对spring data JPA Repository的支持
(7).@EnableTransactionManagement 开启注解式事务的支持
(8).@EnableCaching 开启注解式缓存的支持
通过简单的@Enable*来开启一项功能的支持,从而避免配置大量代码,大大降低使用难度。
原理:
所有的@Enable*注解都有一个@import注解,@import是用来导入 配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的bean。
这些导入配置的方式主要分为以下三种类型:
第一类:直接导入配置类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}编写上述代码类,可查看SchedulingConfiguration源码。
第二类:依据条件选择配置类(可在网上查看资料)
第三类:动态注册bean(可在网上查看资料)
7.测试
Maven依赖:
<dependency>
<artifactId>spring-test</artifactId>
<groupId>org.springframework</groupId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<artifactId>junit</artifactId>
<groupId>junit</groupId>
<version>4.11</version>
</dependency>
文章标题:Spring高级话题
发布时间:2019-11-14, 17:04:21
最后更新:2019-11-14, 17:04:22