0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Springめも

Last updated at Posted at 2022-06-24

DIについて。

「依存性の注入」と言われるもの。

依存とは

他のクラスを利用することを指す。
インターフェースにより、依存度合いを下げることができる(疎結合になる)。

sample.java
//Badな例
//CarクラスとEngineAクラスが蜜結合

import java.util.*;

class EngineA{
    public void boot(){
        System.out.println("EngineA boot");
    }
    public void stop(){
        System.out.println("EngineA stop");
    }
}

class EngineB{
    public void boot(){
        System.out.println("EngineB boot");
    }
    public void stop(){
        System.out.println("EngineB stop");
    }
}

class Car{
    private EngineA engineA;
    public Car(EngineA engineA){
        this.engineA = engineA;
    }
    public void engineStart(){
        this.engineA.boot();
    }
    public void engineStop(){
        this.engineA.stop();
    }
}

class Main {
    public static void main(String[] args) throws Exception {
        
        EngineA engineA = new EngineA();
        Car car = new Car(engineA);//EngineBインスタンスを入れたい時は、Carクラス&利用クラス両方の修正が必要になる。
        car.engineStart();
        car.engineStop();
    }
}
sample.java
//Goodな例
//CarクラスとEngineAクラスが疎結合
//インターフェースにより結合度を下げる。

import java.util.*;

interface Engine{
    public void boot();
    public void stop();
}

class EngineA implements Engine{
    public void boot(){
        System.out.println("EngineA boot");
    }
    public void stop(){
        System.out.println("EngineA stop");
    }
}

class EngineB implements Engine{
    public void boot(){
        System.out.println("EngineB boot");
    }
    public void stop(){
        System.out.println("EngineB stop");
    }
}

class Car{
    private Engine engine;
    public Car(Engine engine){
        this.engine = engine;
    }
    public void engineStart(){
        this.engine.boot();
    }
    public void engineStop(){
        this.engine.stop();
    }
}

class Main {
    public static void main(String[] args) throws Exception {
        
        Engine engine = new EngineA();
        Car car = new Car(engine);//EngineBインスタンスに変える場合は、利用クラスも修正だけで済む。
        car.engineStart();
        car.engineStop();
    }
}

注入とは

インターフェースの型にインスタンスを入れることを指す。

sample.java
class Main {
    public static void main(String[] args) throws Exception {
        
        Engine engineA = new EngineA();
        Car car = new Car(engineA);

        Engine engineB = new EngineB();
        Car car = new Car(engineB);

    }
}

ただし以下のようにEngineAをEngineA_Ver2に変えたい時は
利用クラスの実装も変えないといけなくなる。
インスタンス生成してる箇所が100箇所とかあると修正が大変になる。

sample.java
class EngineA_ver2 implements Engine{
    public void boot(){
        System.out.println("EngineA_ver2 boot");
    }
    public void stop(){
        System.out.println("EngineA_ver2 stop");
    }
}

class Main {
    public static void main(String[] args) throws Exception {
        
        //Engine engineA = new EngineA();
        Engine engineA = new EngineA_ver2();
        Car car = new Car(engineA);

    }
}

ではどうするか。
Factoryを使う。
そうすることでインスタンスを入れ変えたい時は
Factoryを変えてあげるだけになる。

sample.java
class EngineFactory{
        
    public static Engine CreateEngineA(){
        //return new EngineA();
        new EngineA_ver2();
    }
    
    public static Engine CreateEngineB(){
        return new EngineB();
    }
}

class Main {
    public static void main(String[] args) throws Exception {
        
        Engine engineA = EngineFactory.CreateEngineA();
        Car car = new Car(engineA);
        car.engineStop();
    }
}

シングルトンにするなら以下のように実装する。
※他にも実装方法があるかもしれないがここでは触れない。

sample.java
final class EngineFactory{
    
    private static final Engine engineA = new EngineA();
    private static final Engine engineB = new EngineB();
    
    public static Engine CreateEngineA(){
        return engineA;
    }
    
    public static Engine CreateEngineB(){
        return engineB;
    }
}

SpringのDIについて。

Springにはこの依存性注入(DI)の機能が備わっている。
「DIコンテナ」というものがその役割を担っている。
DIコンテナでDIされるクラスのインスタンス(Beanって言ったりするらしい)を管理しており、
これを必要に応じて注入してくれる。

<DIコンテナ>
---------------------
|                    |
|   <Bean1>          |
|  -----            |
|   |   |            |
|   -----            |
|                    |
|   <Bean2>         |
|  -----            |
|   |   |            |
|   -----            |
|                    |
---------------------

よくある使い方

Springで用意されてるアノテーション(@Controller@RestController@Service@Repository などなど。)があるので、基本的にはそれを各クラスの用途(※)によって、付けることでBean対象とすることができ、使いたいときに@Autowiredを付けると注入してくれる。※例えばトランザクション処理を扱うクラスなら@Repositoryを付けるなど

HelloController.java
package com.example.demo.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.service.impl.HelloService;

@RestController
public class HelloController {
	
	@Autowired
	private HelloService helloService;

	@GetMapping("/hello/{id:.+}")
	public String hello(@PathVariable("id") int userId) {
		return helloService.findOne(userId);
	}
}
HelloService.java
package com.example.demo.service.impl;

public interface HelloService {

	public String findOne(int userId);
}
HelloServiceImpl.java
package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.persistence.repository.HelloRepository;
import com.example.demo.service.impl.HelloService;

@Service 
public class HelloServiceImpl implements HelloService {
	@Autowired
	private HelloRepository helloRepository;
	public String findOne( int id) {
		
		// 1 件 検索 実行      
		String str = helloRepository.findOne(id);
		
		return str;
	} 
}
HelloRepository.java
package com.example.demo.persistence.repository;

import org.springframework.stereotype.Repository;

@Repository 
public class HelloRepository {
	
	public String findOne( int id) {

		//本当はここでDBから値取ってきたりする
		
		String[] tbl = {"yamada","yoshida"};
		
		String str = tbl[id];
		
		return str;
	} 
}

実行結果
image.png

独自で(?)Bean定義したいとき

2つやり方がある。
・コンポーネントスキャン
・メソッドによるBean定義

コンポーネントスキャン

①Bean化したい範囲を決める。(ここではdemo配下を指定)

AppConfig.java
package com.example.demo.config;

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

@Configuration
@ComponentScan(basePackages = {"demo"})
public class AppConfig {

}
FooService.java
package com.example.demo.service;

public interface FooService{
	String method();
}

②Bean化したいクラスに「@Componet」を付ける

FooServiceImpl.java
package com.example.demo.service.impl;

import org.springframework.stereotype.Component;

import com.example.demo.service.FooService;

@Component
public class FooServiceImpl implements FooService {
	
	 public String method() {
		return "hello FooServiceImpl";
	}
}

③Beanをセットしたい@Autowiredを付ける

FooController.java
package com.example.demo.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.service.FooService;

@RestController
public class FooController {

	@Autowired
	private FooService fs;

	@GetMapping("/foodi")
	public String fooDi() {
		return fs.method();
	}
	
}

実行結果
image.png

メソッドによるBean定義

ConfigクラスでBeanにしたいクラスのインスタンスを生成するメソッドを定義して、@Beanを付ける。
これがそのままBeanになる。メソッドの名前はなんでもいい。

FooController.java
package com.example.demo.config;

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

import com.example.demo.service.HogeService;
import com.example.demo.service.impl.HogeServiceImpl;

@Configuration
public class AppConfig2 {

	@Bean
	public HogeService getHogeService() {
		return new HogeServiceImpl();
	}
	
}
HogeService.java
package com.example.demo.service;

public interface HogeService{
	public String method();
}
HogeServiceImpl.java
package com.example.demo.service.impl;

import com.example.demo.service.HogeService;

public class HogeServiceImpl implements HogeService {
	
	public HogeServiceImpl() {
	}
	
	 public String method() {
		return "hello HogeServiceImpl";
	}
}
HogeController.java
package com.example.demo.web.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.service.HogeService;

@RestController
public class HogeController {

	private HogeService hs;

	@Autowired //アノテーションはコンストラクタが単一なら省略可能
	public HogeController(HogeService hs) {
		this.hs = hs;
	}
	
	@GetMapping("/hogedi")
	public String hogeDi() {
		return hs.method();
	}
}

実行結果
image.png

参考文献

https://www.amazon.co.jp/後悔しないためのSpring-Boot-入門書:Spring-解体新書(第2版)-Spring解体新書-ebook/dp/B08XPBPH9C
”4章 DI(依存性の注入)とは”

https://www.slideshare.net/masatoshitada7/spring-boot-jjug
”②Springのコア「DI」「コンテナ」「Bean」”

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?