春天的笔记

关于DI。

被称为“依赖注入”的事物。

依存是指一种关系或情况,其中一个事物或个体对另一个事物或个体产生依赖或依靠的状态。

通过使用其他类来实现(指的是)依赖性可以降低(变得松散耦合)的程度。

//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();
    }
}
//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();
    }
}

注入是什么?

指的是将实例放入接口的类型中。

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个实例生成的地方,修改工作会变得非常复杂。

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);

    }
}

要怎么做呢?
使用工厂。
这样当想要更换实例时,
只需要更改工厂即可。

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();
    }
}

如果要实现单例模式,可以按以下方法进行。
※可能还有其他实现方法,但在此处不作讨论。

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)功能。
它通过一个叫做”DI容器”的组件来实现这个功能。
该DI容器管理着被DI注入的类的实例(也被称为Bean),
并在需要时将其注入。

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

常见的用法

由于Spring提供的注解(@Controller,@RestController,@Service,@Repository等等),基本上可以根据每个类的用途(例如处理事务的类应该添加@Repository注解)来标记它们作为Bean的目标,并且当需要使用时,可以添加@Autowired注解进行注入。

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);
	}
}
package com.example.demo.service.impl;

public interface HelloService {

	public String findOne(int userId);
}
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;
	} 
}
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时。

有两种方法可供选择:
– 组件扫描
– 使用方法定义Bean

组件扫描

①确定要进行 Bean 化的范围(在这里指定为 demo 文件夹下)。

package com.example.demo.config;

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

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

}
package com.example.demo.service;

public interface FooService{
	String method();
}

想将一个类转化为Bean,可以在该类上标注”@Component”。

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";
	}
}

我想要一个带有@Autowired注释的Bean的设置。

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。方法的名字可以任意取。

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();
	}
	
}
package com.example.demo.service;

public interface HogeService{
	public String method();
}
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";
	}
}
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

文献引用

“4章 DI(依存性注入)的概念是什么”

https://www.slideshare.net/masatoshitada7/spring-boot-jjug 的第二页展示了Spring的核心概念,包括”DI”、”容器”和”Bean”。

bannerAds