「Spring Boot実戦」学習(二):Springの常用配置


記事の目次
  • springの基本構成
  • Scope
  • Spring ELとリソース呼び出し
  • Benの初期化と廃棄
  • Profile
  • Apple Event
  • Springの高級話題
  • Spring Aware
  • マルチスレッド
  • 計画タスク
  • 条件注
  • コンボ注釈とメタ注釈
  • テスト
  • スプリングの基本構成
    Scrope
    Scopeでは、Spring容器がビーンをどのように作成するかの例を述べている.SpringのScropeには以下のような種類があります.
  • Singletonは、一つのSpring容器の中で一つのBeanだけのインスタンスであり、これはデフォルトの構成である.単例です
  • Prottypeは、毎回ビーンを作成する例
  • を呼び出します.
  • Requestは、Webプロジェクトにおいて、http requestごとにビーンの例を新たに作成する.
  • Sessionは、Webプロジェクトにおいて、http sessionごとにビーンの新しいインスタンスを作成する.
  • Global Sessionは、potalアプリケーションで、global http sessionごとにビーンの新しい例を作成します.
  • 使用例
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;
    
    @Service
    @Scope("prototype")
    public class DemoPrototypeService {
    
    }
    
    Spring ELとリソースコール
    spring開発では、一般ファイル、URL、プロファイル、システム環境変数などを含め、Springの表現言語を使ってリソースの注入を行うことができます.
    サンプルコードは以下の通りです.
    pom.xml添加
    <dependency>
        <groupId>commons-iogroupId>
        <artifactId>commons-ioartifactId>
        <version>2.3version>
    dependency>	
    
    @Service
    public class DemoService {
    	
    	@Value("      ")
    	private String another;
    
    	public String getAnother() {
    		return another;
    	}
    
    	public void setAnother(String another) {
    		this.another = another;
    	}	
    }
    
    
    @Configuration
    @ComponentScan("com.xhf.sample4")
    //              
    @PropertySource("classpath:com/xhf/sample4/test.properties")
    public class ElConfig {
    
    	//     
    	@Value("I love you")  
    	private String normal;
    	
    	//        
    	@Value("#{systemProperties['os.name']}")
    	private String osName;
    	
    	//         
    	@Value("#{T(java.lang.Math).random()*100.0}")
    	private double randomNumber;
    	
    	//    bean   。demoService   bean     
    	@Value("#{demoService.another}")
    	private String fromAnother;
    	
    	//      
    	@Value("classpath:com/xhf/sample4/test.txt")
    	private Resource testFile;
    	
    	//      
    	@Value("http://www.baidu.com")
    	private Resource testUrl;
    	
    	//      
    	@Value("${book.name}")
    	private String bookName;
    	
    	
    	//Environment          
    	@Autowired
    	private Environment environment;
    	
    	//              Bean
    	@Bean
    	public static PropertySourcesPlaceholderConfigurer propertyConfigure() {
    		return new PropertySourcesPlaceholderConfigurer();
    	}
    	
    	
    	public void outputResource() {
    		System.out.println(normal);
    		System.out.println(osName);
    		System.out.println(randomNumber);
    		System.out.println(fromAnother);
    		try {
    			System.out.println(IOUtils.toString(testFile.getInputStream()));
    			System.out.println(IOUtils.toString(testUrl.getInputStream()));
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		System.out.println(bookName);
    		
    		System.out.println(environment.getProperty("book.name"));
    	}
    	
    }
    
    
    public class Main {	
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context
    		= new AnnotationConfigApplicationContext(ElConfig.class);
    		
    		ElConfig resourceService = context.getBean(ElConfig.class);
    		
    		resourceService.outputResource();
    		
    		context.close();
    		
    	}
    	
    }
    
      :
    I love you
    Linux
    37.23290117950025
          
    hello world
    <!DOCTYPE html>
    <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8>......    
    
    spring boot
    spring boot
    
    
    Beanの初期化と廃棄
    SpringはBeanの初期化と廃棄時にいくつかの操作ができます.次の2つの方法を提供します.
  • Java構成の方式:@BeanのinitMethodとdestroyMethodを使用する(xml構成のinit-methodとdestroy-methodに相当する)
  • 注釈の方式:JSR-250@PostCostructと@Predestry
  • を利用します.
    例:
    public class BeanWayService {
    	
    	public void init() {
    		System.out.println("@Bean-init-method");
    	}
    	
    	public BeanWayService() {
    		super();
    		System.out.println("       -BeanWayService");
    	}
    	
    	public void destroy() {
    		System.out.println("@Bean-destroy-method");
    	}
    	
    	
    }
    
    @Component
    public class JSR250WayService {
    	
    	@PostConstruct
    	public void init() {
    		System.out.println("JSR250-init-method");
    	}
    	
    	public JSR250WayService() {
    		super();
    		System.out.println("       -JSR250WayService");
    	}
    	
    	@PreDestroy
    	public void destroy() {
    		System.out.println("JSR250-destroy-method");
    	}
    	
    }
    
    @Configuration
    @ComponentScan("com.xhf.sample5")
    public class PrePostConfig {
    
    	@Bean(initMethod="init", destroyMethod="destroy")  //                   
    	BeanWayService beanWayService() {
    		return new BeanWayService();
    	}
    	
    	
    }
    
    public class Main {
    	
    	
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context
    		= new AnnotationConfigApplicationContext(PrePostConfig.class);
    		
    		BeanWayService beanWayService = context.getBean(BeanWayService.class);
    		
    		JSR250WayService jsr250WayService = context.getBean(JSR250WayService.class);
    
    		context.close();
    		
    	}
    	
    }
    
    
    Profile
    Profileは、異なる環境で異なる構成を使用するためにサポートされています.
  • は、EvironmentのActive Profilesを設定することにより、現在のcontextが使用する必要がある配置環境を設定する.開発において@Profile注解類または方法を使用して、異なる場合に実用化の異なるビーンを選択することができる.
  • は、jvmのspring.profiles.activeパラメータを設定することにより設定環境を設定する.
  • Webプロジェクトは、Servletのcontext parameterに設定されている.
  • アプリイベントイベント
    Springのイベントは流れに従う必要があります.
  • カスタムイベント、Application Event
  • を継承します.
  • カスタムイベントモニター、Appplication Listener
  • を実現します.
  • 容器を使ってイベントを発表します.
  • コードの例
    カスタムイベント:
    public class DemoEvent extends ApplicationEvent {
    	
    	private static final long serialVersionUID = 1L;
    	
    	private String msg;
    
    	public DemoEvent(Object source, String msg) {
    		super(source);
    		this.setMsg(msg);
    	}
    
    	public String getMsg() {
    		return msg;
    	}
    
    	public void setMsg(String msg) {
    		this.msg = msg;
    	}
    	
    }
    
    事件の傍受
    @Component
    public class DemoListener implements ApplicationListener<DemoEvent>{
    
    	@Override
    	public void onApplicationEvent(DemoEvent event) {
    		String msg = event.getMsg();
    		System.out.println("     bean-demopublisher     :"+msg);
    	}
    
    }
    
    イベントリリース
    @Component
    public class DemoPublisher {
    
    	@Autowired
    	ApplicationContext context;
    	
    	public void publish(String msg) {
    		context.publishEvent(new DemoEvent(this, msg));
    	}
    	
    	
    }
    
    設定ファイル
    @Configuration
    @ComponentScan("com.xhf.sample6")
    public class EventConfig {
    }
    
    実行プロセス
    public class Main {
    	
    	public static void main(String[] args) {
    		
    		AnnotationConfigApplicationContext context
    		= new AnnotationConfigApplicationContext(EventConfig.class);
    		
    		DemoPublisher publisher = context.getBean(DemoPublisher.class);
    		
    		publisher.publish("hello world");
    		
    		context.close();
    	
    	}
    }
    
    Springの高級話題
    Spring Aware
    awareは感知という意味で、SpringはAware関連のインターフェースを提供して使用する目的はビーンにいくつかの容器が持つ資源と機能を呼び出せるようにすることです.本の中では大体この意味です.
    私が理解しているのは、容器そのものの機能インターフェースを暴露して、容器に基づいていくつかの機能を広げてくれます.これに対応すると,ビームと容器の結合性が増強される.
    例のコードは次の通りです.BeanNameAwareを実現するとbean name属性が得られます.Resource Loader Awareを実現すると、コンテナのリソースキャリアが得られます.
    package com.xhf.aware;
    
    import java.io.IOException;
    
    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;
    
    @Service
    public class AwareService implements BeanNameAware, ResourceLoaderAware {
    
    	private ResourceLoader resourceLoader;
    	
    	private String name;
    	
    	
    	@Override
    	public void setResourceLoader(ResourceLoader resourceLoader) {
    		this.resourceLoader = resourceLoader;
    	}
    
    	@Override
    	public void setBeanName(String name) {
    		this.name = name;
    	}
    	
    	public void outputResult() {
    		System.out.println("Bean     :" + name);
    		
    		Resource resource = resourceLoader.getResource("classpath:com/xhf/aware/test.txt");
    		try {
    			String content = IOUtils.toString(resource.getInputStream());
    			System.out.println(content);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    }
    
    
    クラスの設定
    package com.xhf.aware;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("com.xhf.aware")
    public class AwareConfig {	
    }
    
    実行コード
    package com.xhf.aware;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    public class Main {
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class);
    		AwareService awareService = context.getBean(AwareService.class);
    		awareService.outputResult();
    		context.close();
    	}	
    }
    
    結果は以下の通りです
    Bean     :awareService
    hello world!!!!!!!!!!!!
    
    
    マルチスレッド
    Springは、タスクアクチュエータTaskExectorにより、マルチスレッドと同時プログラムを実現します.ThreadPoolTaskExectorを使用して、スレッド池に基づくTaskExectorを実現することができます.実際の開発において、任務は一般的に非阻害的であり、すなわち非同期的である.構成クラスでは、@EnbleAsyncを通じて非同期タスクのサポートを開始し、実際に実行されるBeanの方法で@Aync注釈を使用して、これは非同期タスクであると宣言します.
    クラスの設定
    package com.xhf.taskexecutor;
    
    import java.util.concurrent.Executor;
    
    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;
    
    @Configuration
    @EnableAsync
    @ComponentScan("com.xhf.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 com.xhf.taskexecutor;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class AsyncTaskService {
    
    	@Async
    	public void executeAsyncTask(Integer i) {
    		System.out.println("      :" + i);
    	}
    	
    	@Async
    	public void executeAsyncTaskPlus(Integer i) {
    		System.out.println("      +1:" + (i+1));
    	}
    }
    
    クラスを起動し、非同期のタスクを実行します.
    package com.xhf.taskexecutor;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    
    public class Main {
    
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class);
    		AsyncTaskService taskService = context.getBean(AsyncTaskService.class);
    		for (int i = 0; i < 10; i++) {
    			taskService.executeAsyncTask(i);
    			taskService.executeAsyncTaskPlus(i);
    		}
    		context.close();
    	}
    	
    	
    }
    
    計画的任務
    設定クラスの注釈@EnbleSchedulingで計画タスクに対するサポートを開始し、タスクを実行する方法で@Scheduledを注釈することによって、これは計画的なタスクであると宣言します.
    クラスを設定:
    package com.xhf.schedule;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @Configuration
    @ComponentScan("com.xhf.schedule")
    @EnableScheduling
    public class TaskSchedulerConfig {
    
    }
    
    
    計画タスクを定義:
    package com.xhf.schedule;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    @Service
    public class ScheduledTaskService {
    
    	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    	
    	@Scheduled(fixedRate=5000)
    	public void reportCurrentTime() {
    		System.out.println("  5     ,currentTime: "+dateFormat.format(new Date()));
    	}
    	
    	
    	@Scheduled(cron="0 28 11 ? * *")
    	public void fixTimeExecution() {
    		System.out.println("        ,currentTime: "+dateFormat.format(new Date()));
    	}
    }
    
    
    スタートクラス、計画タスクを実行します.
    package com.xhf.schedule;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Main {
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskSchedulerConfig.class);
    	}
    }
    
    条件の説明
    springは@Conditionalを通じて、ある特定の条件を満たすことによって特定のBeanを作成することができます.
    以下のコード例は、Coditionインターフェースを実現することにより、matches方法を実現して判断条件を構成する.
    package com.xhf.conditional;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class WindowsCondition implements Condition {
    
    	@Override
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    		return context.getEnvironment().getProperty("os.name").contains("Windows");
    	}
    
    }
    
    package com.xhf.conditional;
    
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class LinuxCondition implements Condition {
    
    	@Override
    	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    		return context.getEnvironment().getProperty("os.name").contains("Linux");
    	}
    
    }
    
    一つのインターフェースを定義し、その後に異なる条件に従って異なるオブジェクトを実装します.
    package com.xhf.conditional;
    
    public interface ListService {
    
    	public String showListCmd();
    }
    
    package com.xhf.conditional;
    
    public class WindowsListService implements ListService {
    
    	@Override
    	public String showListCmd() {
    		return "dir";
    	}
    
    }
    
    package com.xhf.conditional;
    
    public class LinuxListService implements ListService{
    
    	@Override
    	public String showListCmd() {
    		return "ls";
    	}
    
    }
    
    設定ファイルは@Condational条件を使って異なるBeanを実装します.
    package com.xhf.conditional;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ConditionConfig {
    	
    	@Bean
    	@Conditional(WindowsCondition.class)
    	public ListService windowsListService() {
    		return new WindowsListService();
    	}
    	
    	@Bean
    	@Conditional(LinuxCondition.class)
    	public ListService linuxListService() {
    		return new LinuxListService();
    	}
    	
    }
    
    クラスを開始
    package com.xhf.conditional;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    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());
    		context.close();
    	}
    	
    }
    
    組み合わせ注解と元注
    元注とは別の注を付けることができます.注釈された注釈を組み合わせ注と呼びます.
    コンビネーションコメントは、その構成のメタ注釈の機能を有する.
    例として、注釈を定義します.
    package com.xhf.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    @ComponentScan
    public @interface MyConfiguration {
    
    	String[] value() default{};
    	
    }
    
    
    ビーンを定義します
    package com.xhf.annotation;
    
    import org.springframework.stereotype.Service;
    
    @Service
    public class DemoService {
    
    	public void outPut() {
    		System.out.println("       Bean	");
    	}
    	
    }
    
    クラスの設定
    package com.xhf.annotation;
    
    @MyConfiguration("com.xhf.annotation")
    public class DemoConfig {
    
    }
    
    クラスを開始
    package com.xhf.annotation;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Main {
    
    	public static void main(String[] args) {
    		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
    		DemoService demoService = context.getBean(DemoService.class);
    		demoService.outPut();
    		context.close();
    	}
    	
    }
    
    テスト
    テスト用の依存性を追加します.
    		<dependency>
    			<groupId>org.springframeworkgroupId>
    			<artifactId>spring-testartifactId>
    			<version>4.1.6.RELEASEversion>
    		dependency>
    	
    		<dependency>
    			<groupId>junitgroupId>
    			<artifactId>junitartifactId>
    			<version>4.11version>
    		dependency>
    
    ビーンを定義します
    package com.xhf.test;
    
    public class TestBean {
    	
    	
    	private String context;
    
    	public TestBean(String context) {
    		super();
    		this.context = context;
    	}
    	
    	public String getContext() {
    		return context;
    	}
    
    	public void setContext(String context) {
    		this.context = context;
    	}
    	
    	
    	
    }
    
    
    プロファイルの実装によって構成クラスが異なります.
    package com.xhf.test;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    
    @Configuration
    public class TestConfig {
    
    	@Bean
    	@Profile("dev")
    	public TestBean devTestBean() {
    		return new TestBean(" form dev profile ");
    	}
    	
    	@Bean
    	@Profile("prod")
    	public TestBean prodTestBean() {
    		return new TestBean(" form prod profile ");
    	}
    	
    	
    }
    
    
    テストケース、
    @RunWith(SpringJUnit 4 Class)はSpring Testcontext Fraameweorkの機能を提供しています.ContectConfigration(clases={TestConfig.class}プロファイルを設定します.Active Profilesが活動のプロファイルを決めに行きます.
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ActiveProfiles;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.xhf.test.TestBean;
    import com.xhf.test.TestConfig;
    
    import junit.framework.Assert;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes={TestConfig.class})
    @ActiveProfiles("prod")
    
    public class DemoBeanIntegrationTests {
    
    	@Autowired
    	private TestBean testBean;
    	
    	
    	@Test
    	public void prodBean() {
    		String expect = " form prod profile ";
    		String actual = testBean.getContext();
    		Assert.assertEquals(expect, actual);
    	}
    }