Spring ContainerにSpring Beanを手動で登録する方法(@Bean)

1. AppConfig.javaに @Configuration, @Bean annotationをつける。
    ```jsx
    package hello.hellospring;
    
    @Configuration
    public class AppConfig {
    
        @Bean
        public MemberService memberService() {
            return new MemberServiceImpl(memberRepository());
        }
    
        @Bean
        public OrderService orderService() {
            return new OrderServiceImpl(memberRepository(), discountPolicy());
        }
    
        @Bean
        public MemberRepository memberRepository() {
            return new MemoryMemberRepository();
        }
    
        @Bean
        public DiscountPolicy discountPolicy() {
            // 前
            // return new FixDiscountPolicy();
            // 後
            return new RateDiscountPolicy();
        }
    }
    ```
    - **@Configurationが付いたAppConfig.javaを設定(構成)情報**として使用する。
    - **@Bean**と書かれたメソッドをすべて呼び出し、返却されたオブジェクトをSpringContainerに登録する。
    - SpringContainerに登録されたオブジェクトを**SpringBean**といいますが、
    - **Spring Bean ストレージ**の中には **Bean名前(キー)** と、**Bean オブジェクト(値)** を持っている。
    - Spring Container
        - Spring Beanリポジトリ                      
            | Bean 名前 | Bean オブジェクト |
            | --- | --- |
            | memberService | MemberServiceImpl@x01 |
            | orderService | OrderServiceImpl@x02 |
            | memberRepository | MemoryMemberRepository@x03 |
            | discountPolicy | RateDiscountPolicy@x04 |
2. SpringContainerに登録されたSpringBeanを照会する。
    - applicationContext。**getBean()、getBeanDefinitionNames()、getBeanOfType()**　メソッドを使って探すことができる。
    - 構成情報を指定しなければならない。
    - 以下の例ではAppConfig.classを構成情報として指定した。
    - new AnnotationConfigApplicationContext(**AppConfig.class**)
    - Annotation Config Application Context は、Application Context を実装しているものの一つである。
    ```jsx
    package hello.hellospring;
    
    public class MemberApp {
        public static void main(String[] args) {
            // 1.直接実装オブジェクトの作成
            // MemberService memberService = new MemberServiceImpl();
            // 2.AppConfigを使用して実装オブジェクトの作成および接続
            // AppConfig appConfig = new AppConfig();
            // MemberService memberService = appConfig.memberService();
            // 3. SpringContainer 使用
            **ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);**
    
            // 4.Beanを出力する
            // 4.1. get Bean() 使用
            //     Beanの名前でBeanオブジェクト（インスタンス）を照会する。
            //     getBean(Bean名前、タイプ)
            //     getBean(タイプ or 具体化タイプ)
            //
            //     > 照会対象Spring Beanがない場合はNoSuch Bean DefinitionException発生
            //     >同じタイプが2つ以上あるとNoUnique Bean DefinitionException発生
            //       -> getBean(Beanの名前、タイプ)を使えばいい。
            MemberService memberService = ac.getBean("memberService", MemberService.class);
            MemberService memberService2 = ac.getBean(MemberService.class);
            MemberServiceImpl memberService3 = ac.getBean(MemberServiceImpl.class);
    
            Member member = new Member(1L, "memberA", Grade.VIP);
            memberService.join(member);
    
            Member findMember = memberService.findMember(1L);
            System.out.println(member == findMember);
    
            // 4.2. getBeanDefinitionNames()を使用
            //      Springに登録されたすべてのBeanの名前を照会する。
            AnnotationConfigApplicationContext aac = new AnnotationConfigApplicationContext(AppConfig.class);
            String[] bdNames = aac.getBeanDefinitionNames();
            for (String bdName : bdNames) {
    
                BeanDefinition bd = aac.getBeanDefinition(bdName);
                // ROLE_APPLICATION = 直接登録したApplicationBean
                // ROLE_INFRASTRUCTURE = Springが内部で使用するBean
                if (bd.getRole() == BeanDefinition.ROLE_APPLICATION) {
                    Object bean = ac.getBean(bdName);
                    System.out.println(bdName + " " + bean);
                    //appConfig hello.hellospring.AppConfig$$EnhancerBySpringCGLIB$$df7a2e26@508dec2b
                    //memberService hello.hellospring.member.MemberServiceImpl@1e4f4a5c
                    //orderService hello.hellospring.order.OrderServiceImpl@37313c65
                    //memberRepository hello.hellospring.member.MemoryMemberRepository@465232e9
                    //discountPolicy hello.hellospring.discount.RateDiscountPolicy@798162bc
    
                }
            }
    
            // 4.3. get Bean Of Type()を使用
            // 特定のタイプのBeanを照会する。
            Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);
            for (String key : beansOfType.keySet()) {
                System.out.println(key + " " + beansOfType.get(key));
            }
            // memberRepository hello.hellospring.member.MemoryMemberRepository@5d908d47
            System.out.println("hhh");
            // 4.4.相続関係
            //     親タイプで照会すると、子タイプもあわせて照会する。
            //     すべてのJavaオブジェクトの最親であるObjectタイプで照会すると、すべてのSpring Beanを照会する。
            Map<String, Object> beansOfTypeObject = ac.getBeansOfType(Object.class);
            for (String key : beansOfTypeObject.keySet()) {
                System.out.println(key + " " + beansOfTypeObject.get(key));
            }
        }
    }
    ```