SpringBoot系列(2)---无配置文件配置基础2

上一篇文章的传送门:SpringBoot系列(1)---无配置文件配置基础1

一、Spring Aware 

其实我在写Spring的博客已经用过了SpringAware ,当时使用的是BeanFactoryAware。其实Aware主要为我们提供获得Spring容器信息和服务的接口,让我们可以在bean中获得很多Spring 提供的服务。当然其实直接使用ApplicatonContext已经获得非常多的服务了。

BeanNameAware                         获得容器中Bean的名称

BeanFactoryAware                      获得当前bean factory,使用factory调用容器服务。

ApplicationContextAware             获得当前的application context。

MessageSourceAware      获得message source 获得文本信息

ApplicationEventPublisherAware 应用事件发布器,同样我们可以使用applicationContext 进行事件发布

ResourceLoaderAware           获得资源加载器,用于读取外部资源文件

@Service
public class AwareService implements BeanNameAware,ResourceLoaderAware{

    private String beanName;
    private ResourceLoader resourceLoader;

    public void setBeanName(String s) {
        this.beanName = s;
    }

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

    public void test() throws IOException {
        System.out.println("Bean name is : " + beanName);
        Resource resource = this.resourceLoader.getResource("classpath:text.txt");
        System.out.println("text.txt -> " + IOUtils.toString(resource.getInputStream()));
    }
}
其中 setBean 和 setResourceLoader 是BeanNameAware 和 ResourceLoaderAware的接口方法。这样我们就可以通过这些方法去获得beanName 和 resourceLoader了。

其实如果我们不去实现ResourceLoaderAware 还可以通过IOC的方式获得ResourceLoader

@Service
public class AwareService implements BeanNameAware{

    private String beanName;

    @Autowired
    private ResourceLoader resourceLoader;

    public void setBeanName(String s) {
        this.beanName = s;
    }

    public void test() throws IOException {
        System.out.println("Bean name is : " + beanName);
        Resource resource = this.resourceLoader.getResource("classpath:text.txt");
        System.out.println("text.txt -> " + IOUtils.toString(resource.getInputStream()));
    }
}

二、Spring多线程

Spring通过任务执行器TaskExecutor实现多线程和并发编程。使用ThreadPoolTaskExecutor可以实现一个基于线程池的TaskExecutor。

我们需要在配置类加上@EnableAsync 启动异步功能,并创建一个taskExecutor方法,返回一个ThreadPoolTaskExecutor,这样就获得了一个基于线程池的TaskExecutor

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
@EnableAsync
public class ApplicationConfig {

    public Executor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.initialize();
        return executor;
    }

}

当然我们没有必要使用 executor.execute(new Runnable() {... 去创建一个任务,将这个任务交给Spring。我们只需要在我们的Bean中对需要异步的方法和类打上@Async就完事了。聪明的你已经猜到了,如果在类中打上@Async就代表整个类所有方法都异步,如果在方法上打@Async就代表这个方法是异步。

@Service
public class AsyncTaskService {

    @Async
    public void executeAsyncTask() throws InterruptedException {
        int sum = 0;
        for(int i=0;i<1000;i++){
            Thread.sleep(10);
            sum+= i;
        }
        System.out.println("executeAsyncTask sum : " + sum);
    }

}
Main方法:

public class App 
{
    public static void main( String[] args ) throws IOException, InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        AsyncTaskService service = context.getBean(AsyncTaskService.class);
        service.executeAsyncTask();
        System.out.println("main finish !");
    }
}
main finish !
executeAsyncTask sum : 499500
Process finished with exit code 0

从输出我们可以看出我们的main方法是没有被阻塞的。


二、@Profile 的升级版 @Conditional

上一篇博客我写了Profile的使用,conditional可以说profile的升级版。conditional可以根据条件获得不同的bean,例如操作系统、日期等等。我们需要实现一个实现condition接口的类。里面会一个matches方法,根据不同的需要放回是否满足条件。

public class WindowsCondition implements Condition {

    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return conditionContext.getEnvironment().getProperty("os.name").toLowerCase().contains("windows");
    }
}
public class MacCondition implements Condition {

    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return conditionContext.getEnvironment().getProperty("os.name").toLowerCase().contains("mac");
    }
}
我们可以根据不同的操作系统获得不同的bean

然后我定义了一个Bean主要去读取文件内容

@Component
public class TextLoader {

    @Autowired
    private ResourceLoader resourceLoader;

    private String path;

    public TextLoader(String path) {
        this.path = path;
    }

    public String fileLoad() throws IOException {
        Resource resource = resourceLoader.getResource(this.path);
        return IOUtils.toString(resource.getInputStream());
    }

}
配置类如下:

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
@EnableAsync
public class ApplicationConfig {

    @Bean("textLoader")
    @Conditional(WindowsCondition.class)
    public TextLoader getWinTextLoader(){
        return new TextLoader("file://C:\\text.txt");
    }

    @Bean("textLoader")
    @Conditional(MacCondition.class)
    public TextLoader getMacTextLoader(){
        return new TextLoader("file:///Users/yanzhichao/Desktop/text.txt");
    }
}
如果是windows 系统我会读取C盘下的text.txt文件,如果是mac会读取桌面的text.txt文件,然后看看我们的Main方法:

public static void main( String[] args ) throws IOException, InterruptedException {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    TextLoader loader = context.getBean(TextLoader.class);
    System.out.println(loader.fileLoad());
}

三、组合注解

可以看到我们的配置类,一大堆配置就不能少写一点配置吗?或者一次性打一个注解就把所有需要的东西都启动上。嗯~可以

@Configuration
@ComponentScan("com.tony")
@EnableAspectJAutoProxy
@EnableAsync
public class ApplicationConfig {
我们会将以上这些annotation配置写到一个annotation当中:

@Configuration
@ComponentScan()
@EnableAspectJAutoProxy
@EnableAsync
public @interface MyConfig {

    //覆盖value参数
    String[] value() default{};
}
最后在我们的配置类当中打上我们写的MyConfig即可
@MyConfig("com.tony")
public class ApplicationConfig {


四、Spring Test

在开始之前我们在maven添加SpringTest的依赖支持:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>${spring.version}</version>
</dependency>

然后我们就可以在Junit当中通过依赖注入获得相关的bean并进行测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@ActiveProfiles("dev")
public class AppTest  {

    @Autowired
    private TextLoader textLoader;

    @Test
    public void testTextLoader() throws IOException {
        String textContent = textLoader.fileLoad();
        System.out.println("textContent : " +textContent);
        Assert.assertEquals("SDFGHJKL\n",textContent);
    }

}

@RunWith 没什么好说的,就是要Junit 有SpringTest的支持。

@ActiveProfiles 是需要测试的profile环境

@ContextConfiguration 是配置类

然后直接测试跑就可以了,但是需要注意的是Spring 需要Junit4.12以上的版本的。

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值