005 Spring アノテーション駆動開発チュートリアル: 4 種類のオブジェクトの作成、警告なしのパッケージ スキャン、スコープの遅延読み込み、条件に応じたオブジェクトの登録、オブジェクトのライフサイクル、4 種類の属性の注入、@Profil スイッチ環境、コマンド ライン

1. 授業前の注意事項

説明:

  1. 開発プロジェクトを統合するには Spring、SpringMvc、MyBatis を使用する必要がありますが写很多配置比较麻烦、SpringBoot や SpingCloud の登場以降はそれが可能になります通过注解代替这些配置文件
  2. SpringBoot、SpringCloud 作为Spring之上的框架大量使用到了それらの基礎となるアノテーションの一部と Spring の原則 (@Conditional、@Import、@EnableXXX など)。
  3. SpringBoot や SpingCloud などのフレームワーク技術については以下のコースで学習します在这些陌生的注解上、以及对Spring原理的理解上,浪费了很多时间ので、ここで一般的なアノテーションと一部のアノテーションの原理を学ぶと、以降のコースの学習が非常に簡単になります。
  4. 概要:SpringBoot、SpringCloud这些框架用到了很多Spring的注解和原理,所以在这里提前学下,这样之后在学习SpringBoot、SpringCloud的时候就比较轻松了。

1 コース知識のフローチャート

ここに画像の説明を挿入

2.IOCコンテナ

1 環境を整える

1.1 プロジェクトを作成する

ここに画像の説明を挿入

1.2 依存関係を追加する

  <dependencies> 
       <!--核心容器所依赖的环境-->
       <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>4.3.12.RELEASE</version>
       </dependency>

   </dependencies>

2 コンポーネントの登録・オブジェクトの作成(アノテーション利用)

説明:

  1. 使用したメソッドは纯注解、コンテナのコンポーネント登録管理と依存関係注入機能の完成です。
  2. いわゆる、注册一个组件以前の春の様子を指します创建一个对象

2.1 方法 1: @Configuration+@Bean を使用する

2.1.1 復習: XML 方法

要件: SpringXML メソッドを使用してbean标签オブジェクトを作成し、属性を追加します。

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="person" class="com.atguigu.bean.Person" scope="prototype" >
            <property name="age" value="18"></property>
            <property name="name" value="zhangsan"></property>
      </bean>

</beans>

pojo类:
ここに画像の説明を挿入

package com.atguigu.bean;

public class Person {
    
    

    private String name;
    private Integer age;

    public Person() {
    
    
    }

    public Person(String name, Integer age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Integer getAge() {
    
    
        return age;
    }

    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

テストクラス:
ここに画像の説明を挿入

package com.atguigu;

import com.atguigu.bean.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest {
    
    

    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person bean = (Person) applicationContext.getBean("person");
        System.out.println(bean);

    }

}



2.1.2 現在: 構成クラス + @Bean

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;

import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类
public class MainConfig {
    
    
   
    //给容器中注册一个Bean,方法的返回值为spring容器所管理的一个Bean对象,
    //          对象的类型为返回值的类型,id默认是用方法名作为id(对象名)
    //修改创建的对象名字:可以直接修改方法名,也可以在注解上指定value属性="对象名",只有一个值value可以省略
    //在配置类的方法上加上此注解,ioc容器启动时就会自动调用这个方法,将方法的返回值
    //  放到ioc容器中,将方法名作为组件的id(即对象名)
    @Bean("person")
    public Person person01(){
    
    
        return new Person("lisi", 20);
    }

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu;

import com.atguigu.bean.Person;
import com.atguigu.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainTest {
    
    

    public static void main(String[] args) {
    
    
        //xml的方式
//        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//        Person bean = (Person) applicationContext.getBean("person");
//        System.out.println(bean);

        //配置类的方式来代替xml的方式
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);

        //查看在容器中创建的组件/对象名
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        for (String name : namesForType) {
    
    
            System.out.println(name);
        }


    }

}

2.2 パッケージのスキャン

2.2.1 復習: XML 方法

:Spring使用注解(@Controller...)前の方法でオブジェクトを作成するには、そのオブジェクトが XML 構成ファイルに含まれている必要があります开启包扫描
ここに画像の説明を挿入

<!-- 包扫描、只要标注了@Controller、@Service、@Repository,@Component -->
<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>

2.2.2 現在: 構成クラス + @ComponentScan (警告なし)

: 以前は、アノテーション開発では構成ファイルでパッケージのスキャンを構成する必要がありましたが、現在はこれだけで済みます在配置类中使用注解配置

コントローラー、サービス、dao レイヤークラス:
ここに画像の説明を挿入

package com.atguigu.controller;

import org.springframework.stereotype.Controller;

@Controller
public class BookController {
    
    
}


-------------------------------


package com.atguigu.service;

import org.springframework.stereotype.Service;

@Service
public class BookService {
    
    
}


-----------------------------


package com.atguigu.dao;

import org.springframework.stereotype.Repository;

@Repository
public class BookDao {
    
    
}

構成クラス:
ここに画像の説明を挿入

package com.atguigu.boot.config;

import com.atguigu.bean.Person;
import com.atguigu.service.BookService;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类,配置类本身也是一个组件对象
/**
 * @ComponentScan :
 *     value:指定要扫描的包
 *     excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
 *     includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
 *          FilterType.ANNOTATION:按照注解
 *          FilterType.ASSIGNABLE_TYPE:按照给定的类型;
 *          FilterType.ASPECTJ:使用ASPECTJ表达式
 *          FilterType.REGEX:使用正则指定
 *          FilterType.CUSTOM:使用自定义规则 :需要写一个类继承对应的接口之后重写方法,在方法里面指定过滤规则。
 *
 * excludeFilters使用举例:
 *   @ComponentScan(value = "com.atguigu",
 *                  excludeFilters = {@Filter(type= FilterType.ANNOTATION, classes={Controller.class, Service.class})}
 *                 )
 *  includeFilters: 之前需要在xml中配置禁用默认的过滤规则,默认的扫描规则就是所有的。现在只需要在此注解添加上useDefaultFilters = false即可。
 */


@ComponentScan(value = "com.atguigu",
               includeFilters = {
    
    
                          @Filter(type= FilterType.ANNOTATION,classes={
    
    Controller.class, Service.class}),
                          @Filter(type= FilterType.ASSIGNABLE_TYPE,classes={
    
    BookService.class}),
                          @Filter(type=FilterType.CUSTOM,classes={
    
    MyTypeFilter.class})
                       },

               useDefaultFilters = false
     )
/* jdk8写重复注解的写法:可以写直接写多个@ComponentScan,来指定不同的扫描策略
   jdk8之前重复注解的写法:
        @ComponentScans(value = {
                @ComponentScan(value = "com.atguigu",
                        includeFilters = {@Filter(type= FilterType.ANNOTATION,classes={Controller.class, Service.class})},
                        useDefaultFilters = false
                     )
                } )   */

public class MainConfig {
    
    

    //给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    //修改创建的对象名字:可以直接修改方法名,也可以在注解上指定value属性="对象名",只有一个值value可以省略
    @Bean("person")
    public Person person01(){
    
    
        return new Person("lisi", 20);
    }

}

カスタム フィルタリング ルールのクラス:

ここに画像の説明を挿入

package com.atguigu.config;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

public class MyTypeFilter implements TypeFilter {
    
    

    /**
     * metadataReader:读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到其他任何类信息的
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
    
    
        // TODO Auto-generated method stub
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();

        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        if(className.contains("er")){
    
    //全类名中,包含er,就返回为true,匹配成功。
            return true;
        }
        return false;//一个都不匹配
    }

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest {
    
    

   // @SuppressWarnings("resource")不提示警告
    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        //查看容器中对象的名字
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
    
    
            System.out.println(name);
        }
    }
}

2.3 @Scope+@Lazy (スコープの遅延読み込み)

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;


import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class MainConfig2 {
    
    

    /**
     * Scope的取值源码说明:
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST  request
     * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION	 sesssion
     * @return\
     * 
     * 
     * @Scope:可以调整作用域
     *      singleton(单实例):Spring容器创建的类默认是单实例的
     * 						  ioc容器启动会调用方法创建对象放到ioc容器中,
     *                        以后每次获取就是直接从容器(map.get())中拿。
     *                        
     *      prototype(多实例):ioc容器启动并不会去调用方法创建对象放在容器中。
     * 					      每次获取的时候才会调用方法创建对象;
     * 
     *      request:同一次请求创建一个实例   不常用 (需要在web环境)
     * 
     *      session:同一个session创建一个实例  不常用 (需要在web环境)
     *
     * @Lazy:懒加载,即容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化。(针对单实例)
     * 		单实例bean:默认在容器启动的时候创建对象,所以想要实现懒加载需要加上@Lazy注解
     * 		多实例:默认就是懒加载,不需要添加注解。
     */
    @Bean("person")
    //@Scope("prototype")
    //@Scope:默认是单实例, 连@Scope注解也不写是单实例,只写了@Scope没有指定值里面的值 那么值默认就是singleton单实例。
    @Lazy 
    public Person person(){
    
    
        System.out.println("给容器中添加Person....");
        return new Person("张三", 25);
    }
}

テストクラス:
ここに画像の説明を挿入

 @Test
    public void test02(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
    
    
			System.out.println(name);
		}

        System.out.println("ioc容器创建完成....");
//        Object bean = applicationContext.getBean("person");
//        Object bean2 = applicationContext.getBean("person");
//        System.out.println(bean == bean2);
    }

2.4 条件に応じた登録(@Conditional)

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;


import com.atguigu.bean.Person;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

//类中组件统一设置,满足当前条件,这个类中配置的所有bean注册才能生效;
@Conditional({
    
    WindowsCondition.class})
@Configuration
public class MainConfig2 {
    
    
    

    /**
     * @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean  可以用在类上,也可以用在方法上。
     * 业务:创建2个对象,bill和linus,默认都可以注册bean,
     *      现在要求:
     *           如果系统是windows,给容器中注册("bill")
     *           如果是linux系统,给容器中注册("linus")
     * 实现步骤: 需要写一个类,继承对应的接口,重写里面的方法,在方法中指定注入规则,
     *          之后使用注解@Conditional标识需要注入的Bean,如果重写规则是true就注入。
     */
    @Bean("bill")
    public Person person01(){
    
    
        return new Person("Bill Gates",62);
    }
    @Conditional(LinuxCondition.class)
    @Bean("linus")
    public Person person02(){
    
    
        return new Person("linus", 48);
    }
}

書き換えられたルール クラス 1:
ここに画像の説明を挿入

package com.atguigu.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断是否windows系统
public class WindowsCondition implements Condition {
    
    

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    
    
        Environment environment = context.getEnvironment();//获取运行环境
        String property = environment.getProperty("os.name");//获取操作系统名
        if(property.contains("Windows")){
    
    
            return true;//如果是true匹配成功,如果是false匹配失败
        }
        return false;
    }

}


書き換えられたルール クラス 2:

package com.atguigu.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断是否linux系统
public class LinuxCondition implements Condition {
    
    

    /**
     * ConditionContext:判断条件能使用的上下文(环境)
     * AnnotatedTypeMetadata:注释信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    
    
        // TODO是否linux系统
        //1、能获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //2、获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //3、获取当前环境信息
        Environment environment = context.getEnvironment();
        //4、获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        String property = environment.getProperty("os.name");

        //可以判断容器中的bean注册情况,也可以给容器中注册bean
        boolean definition = registry.containsBeanDefinition("person");
        if(property.contains("linux")){
    
    
            return true;
        }

        return false;
    }

}

テストクラス:

現在 Windows システムを使用しているため、テストのために Linux システムに切り替えることはできません。テスト用にランタイム変数を追加できます。
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

 @Test
    public void test03(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        //动态获取环境变量的值;Windows 10
        String property = environment.getProperty("os.name");
        System.out.println(property);
        for (String name : namesForType) {
    
    
            System.out.println(name);
        }

        Map<String, Person> persons = applicationContext.getBeansOfType(Person.class);
        System.out.println(persons);

    }

2.5 方法 2: @Import (コンポーネントをインポート)

2.5.1 実装方法1:@Import(コンポーネント名)

説明:

  1. @Import (コンテナにインポートされるコンポーネント) を指定すると、コンポーネントはコンテナに自動的に登録され、ID のデフォルトは完全なクラス名になります。
  2. 内部の値は配列型であり、一度に 1 つまたは複数をインポートできます。

構成クラス:
ここに画像の説明を挿入

インポートする必要があるサードパーティ コンポーネントをシミュレートします: Color クラス、Red クラス:

package com.atguigu.bean;

public class Color {
    
    

}
-------------------------

package com.atguigu.bean;

public class Red  {
    
    


}

テストクラス:
ここに画像の説明を挿入

 @Test
 public void testImport04(){
    
    
     AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
     //查看容器中对象的名字
     String[] definitionNames = applicationContext.getBeanDefinitionNames();
     for (String name : definitionNames) {
    
    
         System.out.println(name);
     }


 }

2.5.2 実装 2: @Import+ImportSelector インターフェイス

例証します:

  1. ImportSelector インターフェイス: インポートする必要があるコンポーネントの完全なクラス名の配列を返します。
  2. 実装方法1は、@Importにインポートするコンポーネントのリフレクション名を直接追加してコンポーネントを登録します。
  3. 実装方法2、@Importに追加されるのはクラスのリフレクション名でもありますが、このクラスがImportSelectorインターフェースを実装した後は、登録されたコンポーネントがクラス内でオーバーライドされたメソッドの戻り値になります。

構成クラス:
ここに画像の説明を挿入

コンポーネントをインポートする必要があるクラスを指定します。
ここに画像の説明を挿入

package com.atguigu.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    
    

    //返回值,就是到导入到容器中的组件全类名
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    
    
        //AnnotationMetadata importingClassMetadata:可以获取当前标注@Import注解的类的所有注解信息
        //方法不要返回null值,可以返回空数组
        return new String[]{
    
    "com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
    }

}


テストクラス:
ここに画像の説明を挿入

2.5.3 実装 3: @Import+ImportBeanDefinitionRegistrar

説明:

  1. ImportBeanDefinitionRegistrar: Bean をコンテナに手動で登録します。
  2. ImportBeanDefinitionRegistrar インターフェースを実装するクラスを作成し、内部のメソッドを書き換えて、メソッドに登録する必要があるコンポーネントを指定します。

コンポーネントをインポートする必要があるクラスを指定します。

ここに画像の説明を挿入

package com.atguigu.condition;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import com.atguigu.bean.RainBow;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    
    

    /**
     * AnnotationMetadata:当前类的注解信息
     * BeanDefinitionRegistry,即BeanDefinition注册类:
     * 		把所有需要添加到容器中的bean,通过调用BeanDefinitionRegistry.registerBeanDefinition方法,手工注册进来
     *。
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
    

        boolean definition = registry.containsBeanDefinition("com.atguigu.bean.Red");
        boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
        //逻辑:如果容器中有组件Red和Blue,就注册rainBow
        if(definition && definition2){
    
    
            //指定Bean定义信息;(Bean的类型,Bean。。。)
            RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
            //注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", beanDefinition);
        }
    }

}


構成クラス:
ここに画像の説明を挿入
テストクラス:
ここに画像の説明を挿入

2.6 方法 3: FactoryBean 登録コンポーネント

説明:

  1. Spring提供コンポーネントの登録に使用されるFactoryBean。
  2. 方法 1 と方法 2 は通常の Bean を注入し、コンテナーにインポートされるときにコンストラクターを呼び出してオブジェクトを作成します。ここで登録する必要があるのは、getObject() メソッド、getObjectType()、isSingleton() を呼び出すファクトリ Bean であり、返されたオブジェクトはコンテナーに配置されます。
  3. Factory Bean: FactoryBean インターフェースを実装するクラスを定義し、内部のメソッドを書き換えます。

色:

package com.atguigu.bean;

public class Color {
    
    

    private Car car;

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Color [car=" + car + "]";
    }



}

ファクトリ Bean を定義します。
ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.beans.factory.FactoryBean;

//创建一个Spring定义的FactoryBean
//泛型指定需要创建什么类型的对象
public class ColorFactoryBean implements FactoryBean<Color> {
    
    

    //返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
    
    

        System.out.println("ColorFactoryBean...getObject...");
        return new Color();
    }

    //返回对象的类型
    @Override
    public Class<?> getObjectType() {
    
    
        return Color.class;
    }

    //是单例?
    //true:这个bean是单实例,在容器中保存一份
    //false:多实例,每次获取都会创建一个新的bean;
    @Override
    public boolean isSingleton() {
    
    

        return false;
    }

}


ファクトリ Bean をコンテナに追加します。
ここに画像の説明を挿入

/*使用@Bean注解,之前返回的对象是这个方法名colorFactoryBean,
     现在获取的是工厂Bean调用getObject创建的对象*/
@Bean
 public ColorFactoryBean colorFactoryBean(){
    
    
     return new ColorFactoryBean();
 }

テストクラス:
ここに画像の説明を挿入

@Test
public void testImport04(){
    
    
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    //查看容器中对象的名字
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
    
    
        System.out.println(name);
    }

    //工厂Bean获取的是调用getObject创建的对象
    Object bean2 = applicationContext.getBean("colorFactoryBean");
    Object bean3 = applicationContext.getBean("colorFactoryBean");
    System.out.println("bean的类型:"+bean2.getClass());
    System.out.println(bean2 == bean3);

    //加上&前缀获取的是工厂Bean本身,即@Bean注解标识的方法返回值。
    Object bean4 = applicationContext.getBean("&colorFactoryBean");
    System.out.println(bean4.getClass());//class com.atguigu.bean.ColorFactoryBean


}

2.7. まとめ:コンテナ登録コンポーネントのアノテーションメソッド(4種類)

注釈登録コンポーネント:

  1. パッケージスキャン + コンポーネントアノテーション (@Controller/@Service/@Repository/@Component)[ 自己写的类,普通Bean]
  2. @Bean[ 导入的第三方包里面的组件,自己写的类。普通Bean]
  3. @インポート[ 快速给容器中导入一个组件:第三方包里面的组件,自己写的类。普通Bean]
    • 3.1 @Import (コンテナにインポートされるコンポーネント): コンポーネントはコンテナに自動的に登録され、ID のデフォルトは完全なクラス名になります。
    • 3.2 ImportSelector: インポートする必要があるコンポーネントの完全なクラス名の配列を返します。
    • 3.3 ImportBeanDefinitionRegistrar: Bean をコンテナに手動で登録する
  4. Springが提供するFactoryBean( 第三方包里面的组件。工厂Bean)を使用する
    • 4.1 デフォルトで取得されるオブジェクトは、getObject を呼び出したファクトリ Bean によって作成されたオブジェクトです。
    • &4.2 ファクトリ Bean 自体を取得するには、次のようにid の前に 1 を追加する必要があります。&colorFactoryBean

3 Bean のライフサイクル

3.1 方法 1: @Bean で初期化メソッドと破棄メソッドを指定する

3.1.1 単一インスタンス Bean

構成クラス:
ここに画像の説明を挿入

/**
 * 一、bean的生命周期:
 * 		  bean创建---初始化----销毁的过程
 *    容器管理bean的生命周期:
 *        我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 *
 *    1)构造(对象创建)
 * 		  单实例:在容器启动的时候创建对象
 * 		  多实例:在每次获取的时候创建对象
 *    BeanPostProcessor.postProcessBeforeInitialization (方式4的:在初始化方法前调用)
 *    2)初始化:
 * 		  对象创建完成,并赋值好,调用初始化方法
 *    BeanPostProcessor.postProcessAfterInitialization  (方式4的:在初始化方法后调用)
 *    3)销毁:
 * 		  单实例:容器关闭的时候
 * 		  多实例:容器不会管理这个bean;容器不会调用销毁方法,想要销毁可以手动调用销毁方法;
 *
 *
 *  二、指定Bean的初始化和销毁有4种方式:
 *      方式1)、指定初始化和销毁方法;
 * 		        通过@Bean指定init-method和destroy-method;   (解释:在@Bean注解上指定属性来代替原先的xml方式)
 *      方式2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 * 				DisposableBean(定义销毁逻辑);    (解释:让实体类实现对应的初始化和销毁的接口)
 *      方式3)、可以使用JSR250;
 * 		        @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
 * 		        @PreDestroy:在容器销毁bean之前通知我们进行清理工作 (解释:使用2个注解)
 *      方式4)、BeanPostProcessor【interface】:bean的后置处理器,在bean初始化前后进行一些处理工作;
 * 		        postProcessBeforeInitialization:在初始化之前工作
 * 		        postProcessAfterInitialization:在初始化之后工作 (解释:使用后置处理器)
 *
 *
 * 三、BeanPostProcessor原理
 *    遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 *    一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 *
 *    populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 *    initializeBean
 *    {
 *    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 *    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
 *    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *    }
 *
 *
 * 四、Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 *
 * @author lfy
 *
 */

@Configuration
public class MainConfigOfLifeCycle {
    
    
    //方式一:使用@Bean的方式指定初始化和销毁方法
    @Bean(initMethod="init",destroyMethod="detory")
    public Car car(){
    
    
        return new Car();
    }
}

エンティティクラス:

ここに画像の説明を挿入

package com.atguigu.bean;

public class Car {
    
    

    public Car(){
    
    
        System.out.println("car constructor...");
    }

    public void init(){
    
    
        System.out.println("car ... init...");
    }

    public void detory(){
    
    
        System.out.println("car ... detory...");
    }

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfLifeCycle;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_LifeCycle {
    
    
    @Test
    public void test01(){
    
    
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");


        //关闭容器
        applicationContext.close();
    }
}

3.1.2 マルチインスタンスBean

構成クラスを変更します。
ここに画像の説明を挿入

@Configuration
public class MainConfigOfLifeCycle {
    
    
    @Scope("prototype")
    //方式一:使用@Bean的方式指定初始化和销毁方法
    @Bean(initMethod="init",destroyMethod="detory")
    public Car car(){
    
    
        return new Car();
    }

テストクラスを変更します。
ここに画像の説明を挿入

public class IOCTest_LifeCycle {
    
    
    @Test
    public void test01(){
    
    
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        applicationContext.getBean("car");//多实例bean只有在获取时,才会创建对象并初始化
        //关闭容器
        applicationContext.close();//多实例bean不会自动销毁,想要销毁可以手动调用销毁方法。
    }
}

3.2 方法 2: InitializingBean インターフェイスと DisposableBean インターフェイスを実装する

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;

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

/**
 * 一、bean的生命周期:
 * 		  bean创建---初始化----销毁的过程
 *    容器管理bean的生命周期:
 *        我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 *
 *    1)构造(对象创建)
 * 		  单实例:在容器启动的时候创建对象
 * 		  多实例:在每次获取的时候创建对象
 *    BeanPostProcessor.postProcessBeforeInitialization (方式4的:在初始化方法前调用)
 *    2)初始化:
 * 		  对象创建完成,并赋值好,调用初始化方法
 *    BeanPostProcessor.postProcessAfterInitialization  (方式4的:在初始化方法后调用)
 *    3)销毁:
 * 		  单实例:容器关闭的时候
 * 		  多实例:容器不会管理这个bean;容器不会调用销毁方法,想要销毁可以手动调用销毁方法;
 *
 *  二、指定Bean的初始化和销毁有4种方式:
 *      方式1)、指定初始化和销毁方法;
 * 		        通过@Bean指定init-method和destroy-method;   (解释:在@Bean注解上指定属性来代替原先的xml方式)
 *      方式2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 * 				DisposableBean(定义销毁逻辑);    (解释:让实体类实现对应的初始化和销毁的接口)
 *      方式3)、可以使用JSR250;
 * 		        @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
 * 		        @PreDestroy:在容器销毁bean之前通知我们进行清理工作 (解释:使用2个注解)
 *      方式4)、BeanPostProcessor【interface】:bean的后置处理器,在bean初始化前后进行一些处理工作;
 * 		        postProcessBeforeInitialization:在初始化之前工作
 * 		        postProcessAfterInitialization:在初始化之后工作 (解释:使用后置处理器)
 *
 * 三、BeanPostProcessor原理
 *    遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 *    一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 *
 *    populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 *    initializeBean
 *    {
 *    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 *    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
 *    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *    }
 *
 * 四、Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 *
 */
@Configuration
@ComponentScan("com.atguigu.bean")//使用包扫描+注解标识(@compotent)
public class MainConfigOfLifeCycle {
    
    

}

エンティティクラス:
ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;


@Component//使用注解+包扫描的方式注册bean,当然也可以在配置类中使用@Bean的方式
public class Cat implements InitializingBean,DisposableBean {
    
    

    public Cat(){
    
    
        System.out.println("cat constructor...");
    }

    //销毁方法
    @Override
    public void destroy() throws Exception {
    
    
        System.out.println("cat...destroy...");
    }
    //初始化方法
    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        System.out.println("cat...afterPropertiesSet...");
    }

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfLifeCycle;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_LifeCycle {
    
    
    @Test
    public void test01(){
    
    
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

       
        //关闭容器
        applicationContext.close();
    }
}

3.3 方法 3: アノテーション @PostConstruct、@PreDestroy を使用する

:JSR250、Java仕様で提供されるアノテーションが使用可能です。

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;

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

/**
 * 一、bean的生命周期:
 * 		  bean创建---初始化----销毁的过程
 *    容器管理bean的生命周期:
 *        我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 *
 *    1)构造(对象创建)
 * 		  单实例:在容器启动的时候创建对象
 * 		  多实例:在每次获取的时候创建对象
 *    BeanPostProcessor.postProcessBeforeInitialization (方式4的:在初始化方法前调用)
 *    2)初始化:
 * 		  对象创建完成,并赋值好,调用初始化方法
 *    BeanPostProcessor.postProcessAfterInitialization  (方式4的:在初始化方法后调用)
 *    3)销毁:
 * 		  单实例:容器关闭的时候
 * 		  多实例:容器不会管理这个bean;容器不会调用销毁方法,想要销毁可以手动调用销毁方法;
 *
 *  二、指定Bean的初始化和销毁有4种方式:
 *      方式1)、指定初始化和销毁方法;
 * 		        通过@Bean指定init-method和destroy-method;   (解释:在@Bean注解上指定属性来代替原先的xml方式)
 *      方式2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 * 				DisposableBean(定义销毁逻辑);    (解释:让实体类实现对应的初始化和销毁的接口)
 *      方式3)、可以使用JSR250;
 * 		        @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
 * 		        @PreDestroy:在容器销毁bean之前通知我们进行清理工作 
 *                (解释:使用2个注解)
 *      方式4)、BeanPostProcessor【interface】:bean的后置处理器,在bean初始化前后进行一些处理工作;
 * 		        postProcessBeforeInitialization:在初始化之前工作
 * 		        postProcessAfterInitialization:在初始化之后工作 
 *                (解释:使用后置处理器)
 *
 * 三、BeanPostProcessor原理
 *    遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 *    一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 *
 *    populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 *    initializeBean
 *    {
 *    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 *    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
 *    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *    }
 *
 * 四、Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 *
 */

@Configuration
@ComponentScan("com.atguigu.bean")//使用包扫描+注解标识(@compotent)
public class MainConfigOfLifeCycle {
    
    

}

エンティティクラス:
ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class Dog  {
    
    

    public Dog(){
    
    
        System.out.println("dog constructor...");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
    
    
        System.out.println("Dog....@PostConstruct...");
    }

    //容器移除对象之前
    @PreDestroy
    public void detory(){
    
    
        System.out.println("Dog....@PreDestroy...");
    }

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfLifeCycle;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_LifeCycle {
    
    
    @Test
    public void test01(){
    
    
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //关闭容器
        applicationContext.close();
    }
}

3.4 方法 4: ポストプロセッサを使用する

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;

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

/**
 * 一、bean的生命周期:
 * 		  bean创建---初始化----销毁的过程
 *    容器管理bean的生命周期:
 *        我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
 *
 *    1)构造(对象创建)
 * 		  单实例:在容器启动的时候创建对象
 * 		  多实例:在每次获取的时候创建对象
 *    BeanPostProcessor.postProcessBeforeInitialization (方式4的:在初始化方法前调用)
 *    2)初始化:
 * 		  对象创建完成,并赋值好,调用初始化方法
 *    BeanPostProcessor.postProcessAfterInitialization  (方式4的:在初始化方法后调用)
 *    3)销毁:
 * 		  单实例:容器关闭的时候
 * 		  多实例:容器不会管理这个bean;容器不会调用销毁方法,想要销毁可以手动调用销毁方法;
 *
 *  二、指定Bean的初始化和销毁有4种方式:
 *      方式1)、指定初始化和销毁方法;
 * 		        通过@Bean指定init-method和destroy-method;   (解释:在@Bean注解上指定属性来代替原先的xml方式)
 *      方式2)、通过让Bean实现InitializingBean(定义初始化逻辑),
 * 				DisposableBean(定义销毁逻辑);    (解释:让实体类实现对应的初始化和销毁的接口)
 *      方式3)、可以使用JSR250;
 * 		        @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
 * 		        @PreDestroy:在容器销毁bean之前通知我们进行清理工作 (解释:使用2个注解)
 *      方式4)、BeanPostProcessor【interface】:bean的后置处理器,在bean初始化前后进行一些处理工作;
 * 		        postProcessBeforeInitialization:在初始化之前工作
 * 		        postProcessAfterInitialization:在初始化之后工作 (解释:使用后置处理器)
 *
 * 三、BeanPostProcessor原理
 *    遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
 *    一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
 *
 *    populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
 *    initializeBean
 *    {
 *    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
 *    invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
 *    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
 *    }
 *
 * 四、Spring底层对 BeanPostProcessor 的使用;
 * 		bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
 *
 */
@Configuration
@ComponentScan("com.atguigu.bean")//使用包扫描+注解标识(@compotent)
public class MainConfigOfLifeCycle {
    
    

}

ポストプロセッサを作成します。
ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;


/**
 * BeanPostProcessor:后置处理器的接口
 * 后置处理器:初始化前后进行处理工作
 */
@Component //将后置处理器加入到容器中
public class MyBeanPostProcessor implements BeanPostProcessor {
    
    

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    

        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    

        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }

}

テスト方法:
ここに画像の説明を挿入
これら 2 つのメソッドは、前のメソッドの初期化メソッドの前後に実行されることがわかります。
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfLifeCycle;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_LifeCycle {
    
    
    @Test
    public void test01(){
    
    
        //1、创建ioc容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

        //关闭容器
        applicationContext.close();
    }
}

4 属性の割り当て: 共通属性の挿入

4.1 @Value+@PropertySource

設定ファイル:
ここに画像の説明を挿入

#这是因为中文乱码问题,可以在@PropertySource注解上设置编码
person.nickName=\u5C0F\u674E\u56DB

エンティティクラス:
ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.beans.factory.annotation.Value;

public class Person {
    
    

    /**
     * 使用@Value赋值:
     *   写法1:基本数值
     *   写法2:可以写SpEL; #{}   Spring提供的EL表达式
     *   写法3:可以写${};取出配置文件【properties】中的值(在运行环境变量里面的值),
     *         需要在配置类中使用注解@PropertySource 引入外部属性文件
     *         如果获取不到还可以使用设置的默认值:
     *                 @Value("${person.nickName:小明}")
     *                 private String nickName;
     *                 如果person.nickName获取不到值就使用这个默认值 小明
     */
    
    @Value("张三")
    private String name;
    @Value("#{20-2}")
    private Integer age;
    @Value("${person.nickName}")
    private String nickName;

    
    public String getNickName() {
    
    
        return nickName;
    }
    public void setNickName(String nickName) {
    
    
        this.nickName = nickName;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public Integer getAge() {
    
    
        return age;
    }
    public void setAge(Integer age) {
    
    
        this.age = age;
    }

    public Person(String name, Integer age) {
    
    
        super();
        this.name = name;
        this.age = age;
    }
    public Person() {
    
    
        super();
        // TODO Auto-generated constructor stub
    }
    @Override
    public String toString() {
    
    
        return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
    }
    
}

構成クラス:
ここに画像の説明を挿入

package com.atguigu.boot.config;

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

import com.atguigu.bean.Person;


/**
 * 使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中,
 * 加载完外部的配置文件以后使用${}取出配置文件的值
 * 路径方式:
 *     1.文件路径:"file/path/to/file"
 *     2.类路径:"classpath:/com/my/person.properties"  从resources目录下开始
 */
@PropertySource(value={
    
    "classpath:/person.properties"},encoding = "utf-8")
@Configuration
public class MainConfigOfPropertyValues {
    
    

    @Bean
    public Person person(){
    
    
        return new Person();
    }

}

テストクラス:
ここに画像の説明を挿入
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.bean.Person;
import com.atguigu.boot.config.MainConfigOfPropertyValues;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

public class IOCTest_PropertyValue {
    
    
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
    @Test
    public void test01(){
    
    
        printBeans(applicationContext);
        System.out.println("=============");

        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);


        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.nickName");
        System.out.println(property);//配置文件中的值都加载到了环境变量中,所以还可以通过环境变量取值。
        applicationContext.close();
    }

    private void printBeans(AnnotationConfigApplicationContext applicationContext){
    
    
        String[] definitionNames = applicationContext.getBeanDefinitionNames();
        for (String name : definitionNames) {
    
    
            System.out.println(name);
        }
    }

}

5 オートワイヤリング: オブジェクトプロパティの挿入

5.1 方法 1: @Autowired (属性)

説明: これはSpring提供された注釈です。

5.1.1 デフォルトでは、注入はタイプによって優先されます (ケース 1)

構成クラス:
ここに画像の説明を挿入

package com.atguigu.config;

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


/**
 * 自动装配;
 * 		Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
 *
 * 1)、@Autowired:自动注入:      [Spring提供]
 * 		1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
 * 		2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
 * 							applicationContext.getBean("bookDao")
 * 		3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 * 		4)、自动装配默认一定要将属性赋值好,没有就会报错;
 * 			可以使用@Autowired(required=false);即:正常情况下默认为true:属性注册好后一定要赋好值,否则运行时报错。
 * 		                                         修改为false:能找到就找到,找不到就拉到,属性注册好后即便没有赋值,运行时也不会报错。
 * 		5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
 * 				也可以继续使用@Qualifier指定需要装配的bean的名字
 * 		BookService{
 * 			@Autowired
 * 			BookDao  bookDao;
 * 		}
 *
 * 2)、Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
 * 		@Resource:
 * 			可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
 * 			没有能支持@Primary功能没有支持@Autowired(reqiured=false);
 * 		@Inject:
 * 			需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
 *  @Autowired:Spring定义的; @Resource、@Inject都是java规范
 *
 * AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能;
 *
 * 3)、 @Autowired:构造器,方法参数,方法,属性;都是从容器中获取参数组件的值
 * 		1)、[标注在方法上]:(参数从容器中获取;)
 * 		2)、[标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是(可以自动从容器中获取)
 * 		3)、放在方法参数位置:普通方法,构造方法,set get, (参数从容器中获取);
 * 	    4)、使用@Bean方式注册组件,用在@Bean标注的方法参数位置。默认不写@Autowired效果是一样的;都能自动装配 (参数从容器中获取);
 *
 * 4)、自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx),需要实现一些接口。
 *      总接口为Aware,它有很多子接口,我们自定义组件只需要实现实现xxxAware子接口。在创建对象的时候,
 *      会调用接口规定的方法注入相关组件,把Spring底层一些组件注入到自定义的Bean中。
 * 		xxxAware:功能使用xxxProcessor;
 * 			ApplicationContextAware==》ApplicationContextAwareProcessor;
 *
 *
 * @author lfy
 *
 */
@Configuration
@ComponentScan({
    
    "com.atguigu.service","com.atguigu.dao","com.atguigu.controller"})
public class MainConifgOfAutowired {
    
    


}

制御層:
ここに画像の説明を挿入

package com.atguigu.controller;

import com.atguigu.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class BookController {
    
    

    @Autowired
    private BookService bookService;

}

ビジネス層:
ここに画像の説明を挿入

package com.atguigu.service;

import com.atguigu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    
    

    @Autowired
    private BookDao bookDao;

    public void print(){
    
    
        System.out.println(bookDao);
    }
    @Override
    public String toString() {
    
    
        return "BookService [bookDao=" + bookDao + "]";
    }
}

データ層:
ここに画像の説明を挿入

package com.atguigu.dao;

import org.springframework.stereotype.Repository;

//名字默认是类名首字母小写
@Repository
public class BookDao {
    
    

}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConifgOfAutowired;
import com.atguigu.dao.BookDao;
import com.atguigu.service.BookService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {
    
    

    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);
        
        //获取业务层注入dao层的Bean
        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);//输出对象的引用,相当于调用toStrin方法
        
        //获取dao层的Bean
        BookDao bean = applicationContext.getBean(BookDao.class);
        System.out.println(bean);

        applicationContext.close();
    }

}

5.1.2 同じ型、属性名に従って注入される (ケース 2)

構成クラスを変更します。
ここに画像の説明を挿入

@Configuration
@ComponentScan({
    
    "com.atguigu.service","com.atguigu.dao","com.atguigu.controller"})
public class MainConifgOfAutowired {
    
    
	//再添加一个相同类型的BookDao,测试相同类型的属性如何赋值
	// BookDao bookDao2 
    @Bean("bookDao2")
    public BookDao bookDao(){
    
    
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }
}

データ層を変更します: テストの便宜のため。
ここに画像の説明を挿入

package com.atguigu.dao;

import org.springframework.stereotype.Repository;

//名字默认是类名首字母小写
@Repository  //BookDao bookDao
public class BookDao {
    
    
    private String lable = "1";

    public String getLable() {
    
    
        return lable;
    }

    public void setLable(String lable) {
    
    
        this.lable = lable;
    }

    @Override
    public String toString() {
    
    
        return "BookDao [lable=" + lable + "]";
    }
}

テストクラス:
説明:

  1. これで、同じタイプで名前が異なる 2 つのオブジェクト BookDao bookDao2 と BookDao bookDao が存在します。
  2. 业务层BookDao bookDao なので注入されるのは bookDao です。
    ここに画像の説明を挿入ここに画像の説明を挿入
  3. 业务层BookDao bookDao2 に改造されているので、bookDao2 を注入します。
    ここに画像の説明を挿入
    ここに画像の説明を挿入

5.1.3 同じ型、@Qualifierで属性名を指定する(ケース3)

例証します:

  1. これで、同じタイプで名前が異なる 2 つのオブジェクト BookDao bookDao2 と BookDao bookDao が存在します。
  2. ビジネス層は BookDao bookDao2 を書き込みます。これは、当初は同じ型の名前に従って booDao2 を注入しましたが、現在は @Qualifier アノテーションを使用し、型が同じ場合にアノテーションで識別されたオブジェクト名を注入します。

ビジネス層を変更します:
ここに画像の説明を挿入
テストクラス:
ここに画像の説明を挿入

5.1.4 @Autowired(required=false) (ケース 4)

説明:

  • デフォルトでは、自動アセンブリは属性を適切に割り当てる必要があります。属性がない場合は、エラーが報告されます。これを @Autowired(required=false) に変更できます。見つけられる場合は見つかります。見つからない場合はプルします。エラーが報告されます
  • つまり、 @Autowired アノテーションを使用してプロパティを注入する場合、注入は成功する必要があります。そうでない場合は、実行時にエラーが報告されます。
    これを @Autowired(required=false) に変更すると、注入が成功しなかった場合でも実行時にエラーが報告されなくなります。デフォルトは true です。

データ層を変更し、クラスを構成します。コンポーネント (オブジェクト) をコメントアウトします。
ここに画像の説明を挿入

ここに画像の説明を挿入
デフォルトでは: @Autowired(required=true)、属性には登録後に適切な値を割り当てる必要があります。そうでない場合は、実行時にエラーが報告され、
ここに画像の説明を挿入
@Autowired(required=false) に変更されます。それが見つかった場合は、見つけてください。見つからない場合は、それを取得します。属性 登録後に割り当てがなかった場合でも、実行時にエラーは報告されません。
ここに画像の説明を挿入
ここに画像の説明を挿入

5.1.5 同じ型で、@Primary が優先 Bean を指定する (ケース 5)

例証します:

  • 组件相同的类型有多个时@Qualifier を使用して指定します太麻烦。この時点で、@Primary を使用して Spring に自動アセンブリを実行させることができます默认使用首选的bean前提是@Qualifierは使用できません。@Qualifierを使用して指定した後に@Primaryアノテーションを追加しても有効になりません。

構成クラスの変更:
ここに画像の説明を挿入
ビジネス層の変更: @Qualifier のコメントアウト
ここに画像の説明を挿入
この時点では、オブジェクトは 2 つあります: BookDao bookDao2、BookDao bookDao、アノテーションで識別される bookDao2 が優先されます。
ここに画像の説明を挿入
@Qualifier は使用できないことが前提となっており、 @Qualifier を使用して指定した後に @Primary アノテーションを追加しても有効になりません。
ここに画像の説明を挿入
ここに画像の説明を挿入

5.2 方法 2: @Resource と @Inject

説明:

  1. @Resource(JSR250)Spring はと の使用もサポートしています@Inject(JSR330)
  2. java规范提供的注解

5.2.1 @リソース(JSR250)

例証します:

  1. 自動アセンブリ機能は @Autowired のように実現でき、デフォルトではコンポーネント名に従ってアセンブルされます。
  2. @Primary 機能はサポートされません @Autowired(reqiured=false) はサポートされません。
  3. つまり、@Primary では使用できず、false 属性はサポートされません。

ビジネス層を変更します。
ここに画像の説明を挿入

package com.atguigu.service;

import com.atguigu.dao.BookDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class BookService {
    
    

    //@Qualifier("bookDao")
    //@Autowired(required = false)
    //@Resource 默认是按照组件名称进行装配的
    @Resource(name="bookDao2") //也可以自己指定组件名
    private BookDao bookDao;

    public void print(){
    
    
        System.out.println(bookDao);
    }
    @Override
    public String toString() {
    
    
        return "BookService [bookDao=" + bookDao + "]";
    }
}

テスト:
ここに画像の説明を挿入

5.2.2 @インジェクト (JSR330)

説明:javax.injectインポートする必要があるパッケージ和Autowired的功能一样機能なしrequired=false

依存関係を追加します。

<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

ビジネス層を変更します:
ここに画像の説明を挿入
テスト:
ここに画像の説明を挿入

5.3 方法 1: @Autowired (他の場所)

说明:之前方式一@Autowired注解使用在属性上,此外还能放在构造器,参数,方法上使用。

@Autowired: コンストラクター、パラメーター、メソッド、プロパティはすべてコンテナーからパラメーター コンポーネントの値を取得します。

  1. [标注在方法上]: パラメータはコンテナから取得されます。
  2. [标在构造器上]: コンポーネントにパラメーター コンストラクターが 1 つしかない場合、このパラメーター コンストラクターの @Autowired を省略でき、パラメーターの位置にあるコンポーネントをコンテナーから自動的に取得できます。
  3. 放在参数位置:施工方式とセット方式の両方が可能
  4. コンポーネントのメソッドパラメータを設定クラス @Bean のように登録するために使用され、@Autowired はデフォルトで省略可能です。

5.3.1 ケース 1: 共通メソッドにアノテーションを付ける

構成クラス: パッケージ スキャンの追加
ここに画像の説明を挿入

エンティティクラス:
ここに画像の説明を挿入

package com.atguigu.bean;

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

//默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {
    
    

    private Car car;

    public Car getCar() {
    
    
        return car;
    }

    @Autowired
    //标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;
    //方法使用的参数,自定义类型的值从ioc容器中获取
    public void setCar(Car car) {
    
    //写在普通方法上也一样
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Boss [car=" + car + "]";
    }

}

ここに画像の説明を挿入

package com.atguigu.bean;

import org.springframework.stereotype.Component;

@Component
public class Car {
    
    
    public Car(){
    
    
        System.out.println("car constructor...");
    }

    public void init(){
    
    
        System.out.println("car ... init...");
    }

    public void detory(){
    
    
        System.out.println("car ... detory...");
    }
}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.bean.Boss;
import com.atguigu.bean.Car;
import com.atguigu.bean.Color;
import com.atguigu.config.MainConifgOfAutowired;
import com.atguigu.service.BookService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {
    
    

    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);

        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);

//        BookDao bean = applicationContext.getBean(BookDao.class);
//        System.out.println(bean);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);//获取BOSS类中通过方法注入的car
        Car car = applicationContext.getBean(Car.class);
        System.out.println(car);//获取容器中的组件car,发现是同一个

        applicationContext.close();

    }

}

5.3.2 ケース 2: コンストラクター上でマークされる

エンティティ クラスを変更します。パラメータ構造を追加し、最初のケースをコメント アウトします。
ここに画像の説明を挿入

package com.atguigu.bean;

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

//默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {
    
    

    private Car car;

    //构造器要用的组件,都是从容器中获取
    @Autowired //如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
    public Boss(Car car){
    
    
        this.car = car;
        System.out.println("Boss...有参构造器");
    }

    public Car getCar() {
    
    
        return car;
    }

    //@Autowired
    //标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;
    //方法使用的参数,自定义类型的值从ioc容器中获取
    public void setCar(Car car) {
    
    
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Boss [car=" + car + "]";
    }

}

テスト 1:
ここに画像の説明を挿入

テスト 2 :

  1. コンポーネントにパラメーター化されたコンストラクターが 1 つしかない場合、このパラメーター化されたコンストラクターの @Autowired を省略でき、パラメーターの位置にあるコンポーネントをコンテナーから自動的に取得できます。
  2. 構築メソッド上、構築メソッドのパラメータ上で、アノテーション @Autowired を保存できます。

ここに画像の説明を挿入

ここに画像の説明を挿入

5.3.3 ケース 3: メソッドのパラメータ位置にアノテーションを付ける

説明: 構築メソッド、共通メソッド、および set get メソッドはすべてパラメータ位置にマークできます。

エンティティ クラスを変更します。
ここに画像の説明を挿入

package com.atguigu.bean;

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

//默认加在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {
    
    

    private Car car;

    //构造器要用的组件,都是从容器中获取
    //如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
    //  这个省略指的是构造方法的上和参数上都可以省。
    public Boss(@Autowired Car car){
    
    
        this.car = car;
        System.out.println("Boss...有参构造器");
    }

    public Car getCar() {
    
    
        return car;
    }

    //@Autowired
    //标注在方法,Spring容器创建当前对象,就会调用方法,完成赋值;
    //方法使用的参数,自定义类型的值从ioc容器中获取
    public void setCar( Car car) {
    
    
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Boss [car=" + car + "]";
    }

}

テストクラス:
ここに画像の説明を挿入

5.3.4 ケース 4: @Bean によってマークされたメソッドパラメータの位置

エンティティクラスを追加します。
ここに画像の説明を挿入

package com.atguigu.bean;

public class Color {
    
    

    private Car car;

    public Car getCar() {
    
    
        return car;
    }

    public void setCar(Car car) {
    
    
        this.car = car;
    }

    @Override
    public String toString() {
    
    
        return "Color [car=" + car + "]";
    }

}

構成クラスを変更します。
ここに画像の説明を挿入

/**
 * @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
 * @param car
 * @return
 */
@Bean
public Color color(@Autowired Car car){
    
     //@Autowired可以省略
    Color color = new Color();
    color.setCar(car);
    return color;
}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.bean.Boss;
import com.atguigu.bean.Car;
import com.atguigu.bean.Color;
import com.atguigu.config.MainConifgOfAutowired;
import com.atguigu.service.BookService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {
    
    

    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);

        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);

//        BookDao bean = applicationContext.getBean(BookDao.class);
//        System.out.println(bean);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);
        Car car = applicationContext.getBean(Car.class);
        System.out.println(car);

        Color color = applicationContext.getBean(Color.class);
        System.out.println(color);
        System.out.println(applicationContext);

        applicationContext.close();


    }

}

5.4 方法 3: Spring コンテナーの基礎となるコンポーネントへの意識的なインジェクション

説明:

  1. カスタム コンポーネントが Spring コンテナの下部にあるコンポーネントを使用したい場合は(ApplicationContext,BeanFactory,xxx)、対応するインターフェイスを実装する必要があります总接口为Aware,它有很多子接口
  2. カスタム コンポーネントは、xxxAware サブインターフェイスを実装するだけで済みます。オブジェクトを作成すると、
    インターフェースで指定されたメソッドが呼び出されて関連コンポーネントがインジェクトされ、Spring の下部にある一部のコンポーネントがカスタム Bean にインジェクトされます。

ここに画像の説明を挿入

エンティティ クラスを記述します。
例:

  • ApplicationContextAware: IOC コンテナの自動挿入にご協力ください
  • BeanNameAware: コンポーネント名
  • EmbeddedValueResolverAware: 値リゾルバー
    ここに画像の説明を挿入
package com.atguigu.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
    
    

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        // TODO Auto-generated method stub
        System.out.println("传入的ioc:"+applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
    
    
        // TODO Auto-generated method stub
        System.out.println("当前bean的名字:"+name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
    
    
        // TODO Auto-generated method stub
        String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
        System.out.println("解析的字符串:"+resolveStringValue);
    }




}

テストクラス:
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.bean.Boss;
import com.atguigu.bean.Car;
import com.atguigu.bean.Color;
import com.atguigu.config.MainConifgOfAutowired;
import com.atguigu.service.BookService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {
    
    

    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConifgOfAutowired.class);

        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);

        //BookDao bean = applicationContext.getBean(BookDao.class);
        //System.out.println(bean);

        Boss boss = applicationContext.getBean(Boss.class);
        System.out.println(boss);
        Car car = applicationContext.getBean(Car.class);
        System.out.println(car);

        Color color = applicationContext.getBean(Color.class);
        System.out.println(color);
        System.out.println(applicationContext);
        applicationContext.close();
    }

}

5.5: @Profil は環境に応じて Bean を登録します

5.5.1 @Profil環境構築(環境表現の追加なし)

依存関係を追加します。

<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
   <dependency>
       <groupId>c3p0</groupId>
       <artifactId>c3p0</artifactId>
       <version>0.9.1.2</version>
   </dependency>

   <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
   <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.44</version>
   </dependency>

構成クラスの作成: 環境内に @Profile で識別される Bean がありません
ここに画像の説明を挿入

package com.atguigu.config;


import com.atguigu.bean.Yellow;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;

/**
 * Profile:
 * 		Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 *
 * 开发环境、测试环境、生产环境;
 * 数据源:(/A)(/B)(/C);
 *
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 *
 * 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境@Profile("default")=@Profile()
 * 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 3)、没有标注环境标识的bean在,任何环境下都是加载的;
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    
    

    @Value("${db.user}") //获取配置文件的值,方式一:直接加在属性上
    private String user;

    private StringValueResolver valueResolver;
    //获取配置文件的值,方式三:继承值解析器的接口EmbeddedValueResolverAware来获取
    private String  driverClass;

    @Bean("testDataSource")
    //获取配置文件的值,方式二:加在方法的参数上
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }


    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    //获取配置文件的值,方式三:继承值解析器的接口来获取
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
    
    
        // TODO Auto-generated method stub
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }

}

設定ファイル:
ここに画像の説明を挿入

db.user=root
db.password=root
db.driverClass=com.mysql.jdbc.Driver

テスト クラス: @Profile アノテーションは、環境内の Bean を識別するために使用されません。現時点では、ロードできるデータ ソースは 3 つあります。
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfProfile;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.sql.DataSource;

public class IOCTest_Profile {
    
    


    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(MainConfigOfProfile.class);

        String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
        for (String string : namesForType) {
    
    
            System.out.println(string);
        }


        applicationContext.close();
    }

}

5.5.2 テスト: 環境フラグ(@value)を追加したBean

例証します:

  1. @Profil: Spring は、現在の環境に応じて一連のコンポーネントを動的にアクティブ化し、切り替える機能を提供します。
  2. 環境識別子でマークされていない Bean は、どの環境にもロードされます。

5.5.2.1 環境ロゴ Bean の追加 (アクティブ化されていない)

说明: 環境マークが付いている Bean は、環境がアクティブ化されている場合にのみコンテナに登録でき、アクティブ化されていない場合、Bean はロードされません。
ここに画像の説明を挿入

package com.atguigu.config;


import com.atguigu.bean.Yellow;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;

/**
 * Profile:
 * 		Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
 *
 * 开发环境、测试环境、生产环境;
 * 数据源:(/A)(/B)(/C);
 *
 *
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
 *
 * 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境@Profile("default")=@Profile()
 * 2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
 * 3)、没有标注环境标识的bean在,任何环境下都是加载的;
 */

@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    
    

    @Value("${db.user}") //获取配置文件的值,方式一:直接加在属性上
    private String user;

    private StringValueResolver valueResolver;
    //获取配置文件的值,方式三:继承值解析器的接口EmbeddedValueResolverAware来获取
    private String  driverClass;


    //数据源1:测试
    @Profile("test")
    @Bean("testDataSource")
    //获取配置文件的值,方式二:加在方法的参数上
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    //数据源2:开发
    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    //数据源3:生产
    @Profile("prod")
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
    
    
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    //获取配置文件的值,方式三:继承值解析器的接口来获取
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
    
    
        // TODO Auto-generated method stub
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }

}

現時点ではアクティブ化されておらず、データ ソースがないことがわかります。
ここに画像の説明を挿入

5.5.2.2 デフォルトで有効化されたデフォルトの環境ロゴを使用する

: 何も書かないか、 @Profile("default") を指定します。これは、デフォルト環境を使用することを意味します。
ここに画像の説明を挿入

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

5.5.2.3 コマンドラインパラメータを使用した環境のアクティブ化

説明: コマンドラインの動的パラメーターを使用します: 仮想マシンのパラメーターの位置で -Dspring.profiles.active=test をロードします

コンポーネントを追加します。
ここに画像の説明を挿入

  //此时就有了2个test环境时的组件。
    @Profile("test")
    @Bean
    public Yellow yellow(){
    
    
        return new Yellow();
    }

ここに画像の説明を挿入
ここに画像の説明を挿入
テスト メソッドではデータ ソースの名前のみが出力されるため、黄色は表示されません。
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入

5.5.2.4 特定の環境をアクティブ化するコード

注意: パラメータなしのコンストラクタを使用しますが、パラメータ付きコンストラクタを使用する場合は、構成クラスの起動環境がロードされ、構成クラスの環境はまだセットアップされていません。
ここに画像の説明を挿入

package com.atguigu.test;

import com.atguigu.config.MainConfigOfProfile;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.sql.DataSource;

public class IOCTest_Profile {
    
    

    //1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
    //2、代码的方式激活某种环境;
    @Test
    public void test01(){
    
    
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext();

        //1、创建一个applicationContext
        //2、设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("dev");
        //3、注册主配置类
        applicationContext.register(MainConfigOfProfile.class);
        //4、启动刷新容器
        applicationContext.refresh();

        String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
        for (String string : namesForType) {
    
    
            System.out.println(string);
        }


        applicationContext.close();
    }

}

5.5.2.5 @Profile を構成クラスに記述する

: 設定クラスに記述することもでき、指定された環境にある場合にのみ、配置类里面的所有配置全体が有効になります。

ここに画像の説明を挿入
テスト環境はクラスで使用され、dev がアクティブ化されるため、クラス内の設定は有効になりません。
ここに画像の説明を挿入
テスト環境に切り替えて、黄色のBeanを出力するコードを追加します。
ここに画像の説明を挿入

Yellow yellow = applicationContext.getBean(Yellow.class);//获取yellow的bean
System.out.println(yellow);

ここに画像の説明を挿入

5.6 まとめ:アノテーションに属性を注入する方法(4種類)

  1. @Value: (通常のプロパティを挿入)
    • 書き方1:基本値
    • 書き方2:Springが提供するSpEL; #{} EL式を記述できます
    • 書き方3: ${}と記述し、設定ファイル[properties]の値(実行環境変数の値)を取り出し、外部プロパティファイルをインポートするには設定クラス内の@PropertySourceアノテーションを使用する必要がある
  2. @Autowired:デフォルトでは、注入はタイプによって行われ、同じタイプは名前によって注入されます。(オブジェクトのプロパティを挿入)
    • 使用目的: プロパティ、メソッド、コンストラクター、パラメーター、 @Qualifier アノテーションとともに使用
    • @Qualifier: @Autowired と組み合わせて使用​​され、タイプが同じ場合、このアノテーションを使用してプロパティ名の注入を指定できます。
    • false 関数があり、@Primary とともに使用できます。
    • Spring によって提供される注釈。
  3. @Resource (JSR250)+ @Inject (JSR330): (インジェクションオブジェクトのプロパティ)
    • @リソース(JSR250):
      • 使用場所: プロパティ、セッター メソッド
      • デフォルトでは、属性名に従って注入され、型に従って同じ属性名が注入されます。
      • 注釈に名前を直接指定し、指定された名前に従って注入することができます
      • false 関数はなく、@Primary では使用できません。
    • @インジェクト(JSR330):
      • 使い方は @Autowired と同じですが、false 関数がなく、@Primary と併用できる点が異なります。
    • これら 2 つのアノテーションは Java が提供する仕様です。
  4. Spring コンテナの基礎となるコンポーネントに注入できる Aware のサブインターフェイスを実現します。(オブジェクトのプロパティを挿入)

3.Aop機能テスト

https://www.bilibili.com/video/BV1gW411W7wy?p=27

1 Aop原理:@EnableAspectJAutoProxy

おすすめ

転載: blog.csdn.net/aa35434/article/details/123615755