Spring註解驅動(三)Bean自動裝配

一、自動裝配方式

Spring利用依賴注入(DI),完成對ioc容器中各個組件的依賴關係賦值。

自動裝配的核心實現原理:

調用AutowiredAnnotationBeanPostProcessor:後置處理器,來解析完成自動裝配功能。

  1. @Autowired:spring定義的註解
  2. @Resource(JSR250):基於Java規範的註解
  3. @Inject(JSR330):基於Java規範的註解
  4. 自定義組件實現xxxAware的方式

1、@Autowired:spring定義的註解

@Autowired自動注入規則

規則1:

默認優先按照類型去容器中去找對應的組件:annotationConfigApplicationContext.getBean(BookDao.class)找到就賦值

規則2:

如果找到多個相同類型的組件,再將屬性的名稱作爲組件的id去容器中查找。

規則3:

@Qualifier("bookDao2"):使用@Qualifier指定需要裝配的組件id而不是使用屬性名。

規則4:

自動裝配默認一定要將屬性賦值好,沒有就會報錯。可以使用 @Autowired(required = false)去設置,這樣會返回一個null值

規則5:

@Primary:使用這個註解spring進行自動裝配的時候,默認使用首選的Bean,也可以繼續使用@Qualifier指需要裝配的Bean的名字。

@Autowired自動注入標註的位置

@Autowired:構造器,參數,方法,屬性,都是從容器中獲取參數組件值。

  • 標註在構造器上:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以從容器中獲取。
  • 標註在方法上
  • 放在參數位置

2、@Resource(JSR250):基於Java規範的註解

規則:

  • 可以和@Autowired一樣實現自動裝配功能,默認是按照組件名稱進行裝配的
  • 沒有能支持@Primary功能,沒有能支持@Autowired(required = false)功能

3、@Inject(JSR330):基於Java規範的註解

需要導入javax.inject包,和@Autowired功能一樣,但沒有required = false功能。

<dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
</dependency>

1,2,3知識點的實現實例代碼片段:

/***********************Service層***************************/
@Service
public class BookService {

    @Qualifier("bookDao2")
    @Autowired(required = false)
   // @Resource(name = "bookDao2")
   // @Inject
    BookDao bookDao;

    public void print() {

        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

/***********************DAO層***************************/
//名字默認是類名首字母小寫
@Repository
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 + '\'' +
                '}';
    }
}

/***********************配置層***************************/
//配置類
@Configuration
@ComponentScan({"com.tan.service", "com.tan.dao", "com.tan.controller", "com.tan"})
public class MainConfigOfAutowired {

    @Primary
    @Bean("bookDao2")
    public BookDao bookDao() {

        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }
}

/**********************測試啓動層***************************/
//測試啓動層
public class IOCAutowiredTest {

    @Test
    public void test01() {

        //創建容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

        BookService bookService = annotationConfigApplicationContext.getBean(BookService.class);


        System.out.println(bookService);

    }
}

4、自定義組件實現xxxAware的方式

自定義組件想要使用spring容器底層的一些組件(ApplicationContext,BeanFactory,....)

實現步驟:

步驟1:自定義組件實現xxxAware, 在創建對象的時候,會調用接口規定的方法注入相關組件 Aware

步驟2:把spring底層一些組件注入到自定義的bean

步驟3:xxxAware:功能使用xxxProcessor來處理的

如:ApplicationContextAware---->ApplicationContextAwareProcessor​​​​​​

@Component
public class Red implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        System.out.println("傳入的oc:" + applicationContext);

        this.applicationContext = applicationContext;
    }
}

二、利用@Profile註冊bean

@Profile:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件.

  1. 加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中, 默認是default環境.
  2. 寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效.
  3. 沒有標註環境標識的bean,在任何環境下都是加載的.

實例分析:在不同環境下加載不同環境的數據庫連接池

第一步:配置pom文件,將cp30數據連接池和mysql的數據驅動jar包引入進來

<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.5</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:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件
 *
 * 1)、加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中, 默認是default環境
 * 2)、寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效
 * 3)、沒有標註環境標識的bean,在任何環境下都是加載的
 */
//@Profile("test") //寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置開始生效
@PropertySource("classpath:/dbConfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{

    @Value("${db.user}")
    private String user;

    private StringValueResolver stringValueResolver;

    private String driverClass;


    //1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test
    //2、代碼的方式激活某種環境
    @Bean
    public Yellow yellow(){
        return new Yellow();
    }

   // @Profile("default")
    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}") String password) throws PropertyVetoException {

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}") String password) throws PropertyVetoException {

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");

        comboPooledDataSource.setDriverClass(driverClass);

        return comboPooledDataSource;
    }

    @Profile("prod")
    @Bean("prodDataSource ")
    public DataSource dataSourceProd(@Value("${db.password}") String password) throws PropertyVetoException {

        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);
        comboPooledDataSource.setJdbcUrl("jdbc:mysql//localhost:3306/qccr_okr");
        comboPooledDataSource.setDriverClass(driverClass);
        return comboPooledDataSource;
    }

    public void setEmbeddedValueResolver(StringValueResolver resolver) {

        this.stringValueResolver = resolver;

        this.driverClass = stringValueResolver.resolveStringValue("${db.driverClass}");
    }
}

第三步:啓動不同環境進行測試

啓動的方式有兩種:

1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test
2、代碼的方式激活某種環境

使用代碼激活的方式如下:

public class IOCProfileTest {

    //1、使用命令行動態參數設定環境:在虛擬機參數位置加載-Dspring.profile.active=test
    //2、代碼的方式激活某種環境
    @Test
    public void test01() {

        //創建容器
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();

        //1、創建一個 ApplicationContext
        //2、設置需要激活的環境
        annotationConfigApplicationContext.getEnvironment().setActiveProfiles("test","prod");

        //3、註冊主配置類
        annotationConfigApplicationContext.register(MainConfigOfProfile.class);
        //4、啓動刷新容器
        annotationConfigApplicationContext.refresh();

        String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(DataSource.class);

        for (String beanName: beanNamesForType) {
            System.out.println(beanName);
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章