スプリングの三角形を理解!



この文章の目的は?


スプリングコア三角形-IoC/DI、AOP、PSAについて説明します.

IoC vs DI


制御反転(IOC)と依存注入(DI)は全体としては異なる意味を持つ.
IoCは開発者ではなくスプリングによってコードストリームを制御する概念である.次のコードは、開発者がコードストリームを直接制御する例です.
public class A {
	private B b;
    
    public A() {
    	b = new B();
    }
}
逆に、オブジェクトがスプリングコンテナによって管理されている空の場合、@Autowired操作によってオブジェクトを入力することができる.これは、開発者がスプリングコンテナから直接オブジェクトを作成し、直接オブジェクトを管理するのではなく、オブジェクトに注入することを意味します.
public class A {
	@Autowired
	private B b;
}
したがって,IoCは開発者ではなく,スプリングがコードの流れを逆に制御し,これが制御の逆転である.スプリングによって制御されるため,開発者の負担が小さく,SOLIDの原則を遵守しやすく,柔軟なコード構造を用いて開発することができる.
ではDIとは何でしょうか.IoCはスプリングにのみ使用される概念ではなく、広く使用されている用語であるため、スプリングをIoC容器と定義しても、スプリングが提供する機能を明確に説明することはできない.そこで,より核心的な意味を教えるためにDIの概念を採用した.簡単に言えば、DIはIoCプログラミングモデルを実現する方法の一つである.
IoCとDI-「スプリングの中で、IoCは具体的にDI方式で依存性逆転制御を行います!

依存性注入方法


依存注入法は3種類ある.コンストラクション関数と属性を用いた依存性注入は,単純にコードで見るだけで,XMLを用いた依存性注入の方法をより詳細にまとめる.
  • ジェネレータ注入依存性
  • Getter/Setter属性依存性
  • XML依存注入(生成者も属性もサポート)
  • ジェネレータを使用して依存項目を注入する

    public interface Tire {
    	String getBrand();
    }
    public class KoreaTire implements Tire {
    	public String getBrand() {
        	return "코리아 타이어";
        }
    }
    public class AmericaTire implements Tire {
    	public String getBrand() {
        	return "미국 타이어";
        }
    }
    public class Car {
    	Tire tire;
        
        public Car(Tire tire) {
        	this.tire = tire;
        }
        
        public String getTireBrand() {
        	return "장착된 타이어: " + tire.getBrand();
        }
    }
    public class Driver {
    	public static void main(String[] args) {
        	Tire tire = new KoreaTire();
            Car car = new Car(tire);
            System.out.println(car.getTireBrand());
        }
    }

    属性注入依存性の使用


    生成者の依存性注入を用いてタイヤを装着すると、タイヤを交換することができなくなる.運転手がより現実的にタイヤを交換できるように,属性依存注入を用いることができる.ジェネレータを使用する依存注入コードでは、一部のみ変更されます.
    public class Car {
    	Tire tire;
        
    	public Tire getTire() {
        	return tire;
        }
        
        public void setTire(Tire tire) {
        	this.tire = tire;
        }
        
        public String getTireBrand() {
        	return "장착된 타이어: " + tire.getBrand();
        }
    }
    public class Driver {
    	public static void main(String[] args) {
        	Tire tire = new KoreaTire();
            Car car = new Car();
            car.setTire(tire);
            System.out.println(car.getTireBrand());
        }
    }
    💡 属性で依存性を注入するよりも、生成者を使った依存性注入が人気?
    上のタイヤの例を考えてみましょう.実際、私たちは数十年来、車を運転してタイヤを交換する仕事が普通の運転手であることはめったにありません.つまり,現実に頻繁に変化することがなければ,生成者の依存性を用いて注入する傾向がある.

    XML注入依存性の使用


    本ではXMLを総合ショッピングモールの役割として描いている.上記の使用ジェネレータおよび属性の依存注入例では、運転手が直接車およびタイヤを作成した場合、XMLの依存注入で運転手がXMLに登録された車およびタイヤを選択する概念を使用する.したがって、XMLを使用すると、再コンパイルや再配置を必要とせず、XMLファイルを変更するだけでプログラムの実行結果を変更できます.

    XMLデフォルト注入

    <!-- xml 파일 위치 : src/main/java/expert002/expert002.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     
        <bean id="mainTire" class="expert002.KoreaTire"></bean>
        <bean id="americaTire" class="expert002.AmericaTire"></bean>
    
      	<bean id="car" class="expert002.Car"></bean>
    
    </beans>
    public class Driver {
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("expert002/expert002.xml");
            
    		Car car = context.getBean("car", Car.class);
    		Tire tire = context.getBean("mainTire", Tire.class);
    		car.setTire(tire);
    		System.out.println(car.getTireBrand());
    	}
    }

    XML属性の入力

    <!-- xml 파일 위치 : src/main/java/expert002/expert002.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     
        <bean id="mainTire" class="expert002.KoreaTire"></bean>
        <bean id="americaTire" class="expert002.AmericaTire"></bean>
    
        <bean id="car" class="expert002.Car">
          	<property name="tire" ref="mainTire"></property>
      	</bean>
    
    </beans>
    public class Driver {
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("expert002/expert002.xml");
            
    		Car car = context.getBean("car", Car.class);
    		System.out.println(car.getTireBrand());
    	}
    }

    @Autowired注入

    @AutowiredArnovationでは、Springフレームワークがコンフィギュレーション・メソッドを使用することなく、コンフィギュレーション・ファイルに属性を注入できます.
    <!-- xml 파일 위치 : src/main/java/expert002/expert002.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.1.xsd">
     
      	<context:annotation-config />
      
        <bean id="mainTire" class="expert002.KoreaTire"></bean>
        <bean id="americaTire" class="expert002.AmericaTire"></bean>
    
      	<bean id="car" class="expert002.Car"></bean>
    
    </beans>
    public class Car {
    	@Autowired
    	Tire mainTire;
        
        public String getTireBrand() {
        	return "장착된 타이어: " + mainTire.getBrand();
        }
    }
    プライマリタイヤをアメリカンタイヤに設定する場合は、XMLファイルにアメリカンタイヤに対応するスペースを見つけ、idをMainTireに変更します.
    <!-- xml 파일 위치 : src/main/java/expert002/expert002.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                               http://www.springframework.org/schema/context http://www.springframework.org/schema/spring-context-3.1.xsd">
     
      	<context:annotation-config />
      
        <bean id="koreaTire" class="expert002.KoreaTire"></bean>
        <bean id="mainTire" class="expert002.AmericaTire"></bean>
    
      	<bean id="car" class="expert002.Car"></bean>
    
    </beans>
    違う状況を見てみましょう.🤓

    @Autowired-XMLのid属性は存在しません


    下部コードの結果は@Autowiredで正常に動作します.なぜなら、KoreaTireクラスはTireクラスを継承しているからです.
    @Autowired
    Tire tire
    <bean class="expert002.KoreaTire"></bean>
    <bean id="car" class="expert002.Car"></bean>

    @Autowired-XMLのid属性が一致しません


    前述したように、@Autowiredはtype属性よりも優先される.したがって,idが異なっていても正常に動作する.
    @Autowired
    Tire tire
    <bean id="differentTireName" class="expert002.KoreaTire"></bean>
    <bean id="car" class="expert002.Car"></bean>

    @Autowired-XMLにはid属性がなく、同じbeanが2つしかありません。


    結果は失敗です.理由は当然です.idプロパティがなく、同じタイプの2つの空がある場合、springはどの空に一致するべきか分からないからです.
    @Autowired
    Tire tire
    <bean class="expert002.KoreaTire"></bean>
    <bean class="expert002.AmericaTire"></bean>
    <bean id="car" class="expert002.Car"></bean>

    @Autowired-XMLの他のタイプですが、idが一致する場合があります。


    この場合、異なるtypeですが、idが一致してもtypeのスペースが一致します.
    @Autowired
    Tire tire
    <bean class="expert002.KoreaTire"></bean> <!-- 매칭 -->
    <bean id="tire" class="expert002.Door"></bean>
    <bean id="car" class="expert002.Car"></bean>

    @Resource注入

    @Resourceはjava標準言語で、スプリングフレームを使用しなくても使用できます.本の中の筆者は,@Autowiredより@Resource音声の方が適切であると述べている.車の立場では、タイヤが資源のようにより直感的に表現できるからだ.
    ただし、構文ごとに空の属性の優先度が異なることに注意してください.
  • @Autowiredの優先度はtype(class)、後にid
  • @Resourceの優先度はidの次のタイプ(クラス)
  • 💡 @ResourceよりXML属性注入(property)を使用したほうがいいですか?
    本書では@Resourceの方が開発効率は良いが、XMLファイルだけを見ても簡単にDI関係を特定でき、メンテナンス性に優れ、XMLファイルも用途別に分離できるので、XML属性注入(property)を使う方法をお勧めします.

    @Qualifier(""), @Resource(name="")


    XMLファイルを作成する場合、特定のidを使用してクラスの属性名と一致しないように構成する場合は、name属性@Autowiredおよび@Qualifierを使用します.
    <bean id="differentTireName" class="expert002.KoreaTire"></bean>
    <bean id="car" class="expert002.Car"></bean>
    @Autowired
    @Qualifier("differentTireName")
    Tire tire
    @Resource(name = "differentTireName")
    Tire tire

    AOP


    ビュー向けプログラミング(AOP)は,記録,セキュリティ,トランザクションなどが繰り返される横断的な注目点とコア的な注目点を分けて集中的に管理する方法である.AOPによって実現されるコードは、さらなる開発とメンテナンスに有利であり、単一責任原則を適用する.ここでは使い方よりも、特徴だけ整理しておきます.
    AOPで覚えておきたいポイントは大体3つ.
  • プロキシサーバの使用
  • インタフェースベース
  • ランタイムベース
  • AOP用語は@Resourceである.特に、「観察」という言葉を説明すれば、AOPのほうが分かりやすい.
  • Asspect=Advice(いつどこ)+Pointcut(どこ)=いつどこ
  • 💡 Advisor?
    AdvisorはSpring AOPでのみ使用される用語です.Asspectに示すように、Advisorは正式に次のように表示されます.
  • Advisor=1つのAdvisor+1つのPointcut
  • ただし、Springバージョンのアップグレードに伴い、この機能は使用しないことをお勧めします.これは,スプリングの発達に伴い,複数のAdvisorと複数のPointcutを多様な方法で組み合わせて用いることができるからである.
    すなわち,AOPがいつ注目点を横切るかを定義するプログラミング技術であると考えると,容易に実現できる.
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     
      	<aop:asepctj-autoproxy />
      
        <bean id="myAspect" class="aop002.MyAspect"></bean>
      	<bean id="boy" class="aop002.Boy"></bean>
      	<bean id="girl" class="aop002.Girl"></bean>
    
    </beans>
    @Aspect
    public class MyAspect {
    	@Pointcut("execution(* runSomething())")
        private void iampc() {
        	// 의미 없는 코드 블록
        }
    
    	// @Before("execution(* runSomething())")
        @Before("iampc()")
        public void before(JoinPoint joinPoint) {
        	System.out.println("AOP 적용 (before)");
        }
        
        @After("iampc()")
        public void lockDoor(JoinPoint joinPoint) {
        	System.out.println("AOP 적용 (after)");
        }
    }
    上記のコードが宣言に基づいてAOPを適用した場合、POJOとXMLに基づくAOPは以下のようになる.
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     
      	<aop:asepctj-autoproxy />
      
        <bean id="myAspect" class="aop002.MyAspect"></bean>
      	<bean id="boy" class="aop002.Boy"></bean>
      	<bean id="girl" class="aop002.Girl"></bean>
    
      	<aop:config>
          	<aop:pointcut expression="execution(* runSomething())" id="iampc" />
        	<aop:aspect ref="myAspect">
              	<!--
            	<aop:before method="before" pointcut="execution(* runSomething())" /> 
            	<aop:after method="lockDoor" pointcut="execution(* runSomething())" /> 
    			-->
              	<aop:before method="before" pointcut-ref="iampc" />
              	<aop:before method="lockDoor" pointcut-ref="iampc" />
          	</aop:aspect>
      	</aop:config>
    </beans>
    public class MyAspect {
        public void before(JoinPoint joinPoint) {
        	System.out.println("AOP 적용 (before)");
        }
        
        public void lockDoor(JoinPoint joinPoint) {
        	System.out.println("AOP 적용 (after)");
        }
    }

    PSA


    移植可能サービス抽象(PSA)は、一貫したサービス抽象と呼ばれる.サービス抽象化とは、JDBCのようにアダプタモードを利用して汎用インタフェース制御によって同じ動作を実行できるサービス抽象化の多くの技術である.Springは、様々な技術(オブジェクトXMLマッピング-オブジェクトからXMLマッピング)、ORM、キャッシュ、トランザクションなどにPSAを提供する.

    本文の参考

  • Javaオブジェクト向けSpring入門原理の理解
  • https://biggwang.github.io/2019/08/31/Spring/IoC,%20DI%EB%9E%80%20%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C/