第三章:Spring的高级话题

3.1 SpringAware

3.1.1 说明

Spring的依赖注入的最大亮点就是你所有的Bean对Spring容器的存在是没有意识的。Bean之间的耦合度很低。若使用了SpringAware,将会使得Bean和Spring框架耦合。

Bean 说明
BeanNameAware 获得容器中Bean的名称
BeanFactoryAware 获得当前的BeanFactory,调用容器的服务
ApplicationContextAware 当前的Application Context,调用容器的服务
MessageSourceAware 获得Message Source,获得文本信息
ApplicationEventPublisherAware 应用事件发布器,可以发布事件
ResourceLoaderAware 获得资源加载器,可以获取外部资源文件

Spring Aware的目的是为了让Bean获取Spring容器的服务。

3.1.2 实例

1)新增资源aware.txt

Hello,this is a Spring Aware test!

2)Bean的创建

package com.dy.spring_demo.ch3.aware;

import org.apache.commons.io.Charsets;
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;

/**
 * Author:dy_bom
 * Description: 实现BeanNameAware、ResourceLoaderAware接口,获取Bean名称和资源加载的服务。
 * Date:Created in 上午1:07 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Service
public class AwareService implements BeanNameAware, ResourceLoaderAware {
    private String beanName;
    private ResourceLoader resourceLoader;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public String getBeanName() {
        return beanName;
    }

    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

    public void outResult(){
        System.out.println("Bean的名称是:"+beanName);
        Resource resource = resourceLoader.getResource("classpath:com/dy/spring_demo/ch3/aware/aware.txt");
        try {
            System.out.println("ResourceLoader加载的文件内容为:"+ IOUtils.toString(resource.getInputStream(), Charsets.requiredCharsets().lastKey()));
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

3)配置

package com.dy.spring_demo.ch3.aware;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:15 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Configuration
@ComponentScan("com.dy.spring_demo.ch3.aware")
public class AwareConfig {
}

4)运行

package com.dy.spring_demo.ch3.aware;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:16 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class);
        AwareService awareService = context.getBean(AwareService.class);
        awareService.outResult();

        context.close();
    }
}

结果如下

Bean的名称是:awareService
ResourceLoader加载的文件内容为:Hello,this is a Spring Aware test!

3.3 多线程

3.3.1 说明

Spring通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。通过注解@EnableAsync开启对异步任务的支持,并通过在实际执行的Bean中使用@Async注解来声明其是一个异步任务。

3.3.2 实例

1)配置类

package com.dy.spring_demo.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;

/**
 * Author:dy_bom
 * Description: 实现AsyncConfigurer重写方法
 * Date:Created in 上午1:24 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Configuration
@ComponentScan("com.dy.spring_demo.ch3.taskexecutor")
@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;
    }
}

2)Bean的创建

package com.dy.spring_demo.ch3.taskexecutor;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:28 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Service
public class AsyncTaskService {

    @Async  //表明该方法是一个异步方法,注解在类级别,表明该类所有的方法都是异步方法
    public void executorAsyncTask(Integer i){
        System.out.println("执行异步任务:"+i);
    }

    @Async
    public void executorAsyncTaskPlus(Integer i){
        System.out.println("执行异步任务+1:"+(i+1));
    }
}

3)运行

扫描二维码关注公众号,回复: 1752313 查看本文章
package com.dy.spring_demo.ch3.taskexecutor;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:32 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
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.executorAsyncTask(i);
            asyncTaskService.executorAsyncTaskPlus(i);
        }
        context.close();
    }
}

结果如下

执行异步任务:1
执行异步任务+1:1
执行异步任务+1:2
执行异步任务:2
执行异步任务:0
执行异步任务+1:4
执行异步任务:4
执行异步任务:3
执行异步任务+1:3
执行异步任务:6
执行异步任务+1:6
执行异步任务:5
执行异步任务+1:5
执行异步任务:8
执行异步任务+1:8
执行异步任务:7
执行异步任务+1:7
执行异步任务+1:10
执行异步任务:9
执行异步任务+1:9

结果是并发执行而不是顺序执行

3.3 计划任务

3.3.1 说明

首先在配置类注解@EnableSchedule开启对计划任务的支持,然后在需要执行计划任务的方法上注解@Scheduled,声明这是一个计划任务。

3.3.2 实例

1)配置

package com.dy.spring_demo.ch3.taskscheduler;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:44 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Configuration
@ComponentScan("com.dy.spring_demo.ch3.taskscheduler")
@EnableScheduling //开启对执行任务的支持
public class TaskSchedulerConfig {
}

2)Bean

package com.dy.spring_demo.ch3.taskscheduler;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:39 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Service
public class ScheduledTaskService {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss ");

    @Scheduled(fixedRate = 5000) // 声明方法是执行任务,使用fixedRate属性每隔固定事件执行
    public void reportCurrentTime(){
        System.out.println("每隔5秒执行一次:"+dateFormat.format(new Date()));
    }

    @Scheduled(cron = "0 51 01 ? * *") // 使用Corn属性按照指定时间执行,每天01点51分执行
    public void fixTimeExecution(){
        System.out.println("在指定时间:"+dateFormat.format(new Date())+"执行");
    }
}

3)执行

package com.dy.spring_demo.ch3.taskscheduler;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午1:45 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext  context = new AnnotationConfigApplicationContext(TaskSchedulerConfig.class);
    }
}

结果如下:

每隔5秒执行一次:01:50:37 
每隔5秒执行一次:01:50:42 
每隔5秒执行一次:01:50:47 
每隔5秒执行一次:01:50:52 
每隔5秒执行一次:01:50:57 
在指定时间:01:51:00 执行
每隔5秒执行一次:01:51:02 
每隔5秒执行一次:01:51:07 
每隔5秒执行一次:01:51:12 
每隔5秒执行一次:01:51:17 

3.4 条件注解@conditional

3.4.1 说明

注解Conditional根据满足某一个特定条件创建一个特定的Bean。例如,不同分操作系统作为条件,我们将通过实现Condition接口,并重写matches方法来判断调条件。此处不做举例说明

3.5 组合注解与元注解

3.5.1 说明

元注解就是可以注解到其他注解上面的注解,被注解的注解称之为组合注解。组合注解具备注解上其他元注解的功能,例如@RestController(@Controller+@ResponseBody)、。

3.5.2 实例

我们来做一个把@Configuration、 @ComponentScan组合注解
1)组合注解

package com.dy.spring_demo.ch3.annotation;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.lang.annotation.*;

/**
 * Author:dy_bom
 * Description: 组合注解 @Configuration  @ComponentScan
 * Date:Created in 上午2:02 2018/4/2
 * Copyright (c) [email protected] All Rights Reserved.
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@ComponentScan
public @interface DyConfiguration {
    String[] value() default {}; //覆盖Value参数
}

2)配置

package com.dy.spring_demo.ch3.annotation;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午2:06 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@DyConfiguration("com.dy.spring_demo.ch3.annotation")
public class DemoConfig {
}

3)Bean

package com.dy.spring_demo.ch3.annotation;

import org.springframework.stereotype.Service;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午2:04 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
@Service
public class DemoService {
    public void outputResult(){
        System.out.println("从组合注解可以获取Bean");
    }
}

4)执行

package com.dy.spring_demo.ch3.annotation;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Author:dy_bom
 * Description:
 * Date:Created in 上午2:08 2018/4/2
 * Copyright (c)  [email protected] All Rights Reserved.
 */
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
        DemoService demoService = context.getBean(DemoService.class);

        demoService.outputResult();

        context.close();
    }
}

结果如下:

从组合注解可以获取Bean

代码地址:点我
上一篇:Spring常用配置

猜你喜欢

转载自blog.csdn.net/ruben95001/article/details/79783848
今日推荐