深刻學習Spring框架(二)- 註解配置

1.爲何要學習Spring的註解配置?  

  基於註解配置的方式也已經逐漸代替xml。因此咱們必需要掌握使用註解的方式配置Spring。
  關於實際的開發中到底使用xml仍是註解,每家公司有着不一樣的使用習慣。因此這兩種配置方式都須要掌握。
  學習基於註解的IoC配置,首先得有一個認知,即註解配置和xml配置要實現的功能都是同樣的,都是要下降程序間的耦合。只是配置的形式不同。java

2.入門示例

步驟:
  1.導入jar包,相對於以前的,在基於註解的配置中,咱們還要多拷貝一個aop的jar包。spring

  

  2.在classpath下建立一個配置文件applicationContext.xml,並導入約束,基於註解整合時,配置文件導入約束時須要多導入一個context名稱空間下的約束sql

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context/spring-context.xsd
">

</beans>

  3.建立一個用於測試的類,而且加入使用@Component註解,聲明該類容許注入到Spring容器app

import org.springframework.stereotype.Component;
/*
 * @Component 組件註解,spring在啓動的時候掃描對應的包下面的全部類型
 * 若是哪個類上只要有 @Component 註解,說明這個就須要被Spring管理
 * Spring在容器就建立這個類的對象
 * 
 * @Component 屬性介紹
 *     @Component(value="id值")
 *  value :指定 bean 的 id值
 *    能夠不寫,默認bean的id就是當前類名的 首字母小寫
 *    若是寫,「value=」能夠省略,直接"id值"
 * 
 */
@Component("service")
public class Service {
    
    public void say() {
        System.out.println("你好!Spring");
    }
}

  4.往配置文件加入掃描組件配置框架

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context/spring-context.xsd
">
    <!-- 配置spring要進行掃描的組件註解的包(默認包含子包)的位置 -->
    <context:component-scan base-package="com.gjs.service"/>
</beans>

  5.測試代碼ide

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gjs.service.Service;

public class TestSpring {
    @Test
    public void testName() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Service service = context.getBean("service",Service.class);
        service.say();
        
    }
}

3.經常使用註解說明

  3.1 IOC相關注解

  用於被掃描建立對象的註解,統稱爲組件註解。組件包括:@Component,@Controller,@Service,@Repository。它們的做用是標識類爲註解的組件類,啓動Spring框架的程序時,聲明將這些組件類注入到Spring容器裏面。功能相似原來配置文件的<bean>標籤。
其餘它們的功能是同樣的並無本質上的區別,哪爲何會有4個呢?
  Spring初版註解的實現(spring 2.5),就是使用一個@Component。從3.0之後,做者認爲根據分層的須要,把它拆成了四個。爲了可讓開發人員,可見便可得,一看到註解,當即知道類的性質。因此分紅了四個。函數

規範:單元測試

@Controller:用於聲明表示層的組件註解
@Service:用於聲明服務層的組件註解
@Repository:用於聲明持久層的組件註解
@Component:用於聲明三層之外的組件註解
除了@Controller在SpringMVC裏面有強制的要求,SpringMVC的表示層必須使用@Controller組件註解。其餘狀況不按規範使用也不會有問題,但既然是規範就要遵照。學習

 

  @Scope:指定做用範圍,等同於Xml配置<bean>標籤中的scope測試

@Component("service")
@Scope("prototype")
public class Service {
    
    public void say() {
        System.out.println("你好!Spring");
    }
}

  @PostConstruct:初始化方法註解,等同於Xml配置<bean>標籤中的init-method

@PostConstruct 
public void init() {
    System.out.println("初始化方法執行了");
}

 

  @PreDestroy:銷燬方法註解,等同於Xml配置<bean>標籤中的destroy-method

@PreDestroy
public void destroy() {
     System.out.println("銷燬方法執行了");
}

 

  3.2 依賴注入的註解

  Spring提供了兩套用註解依賴注入的解決方案
    1.@Autowired +@Qualifier():是Spring定義的標籤
    2.@Resouce:是J2EE的規範

  

@Autowired +@Qualifier()

@Autowired +@Qualifier()有三種注入的方式:
  1.在字段上面注入
  2.在方法上面注入
  3.在構造方法上面注入

示例:

總體結構:

  CustomeService接口:

package com.gjs.service;

public interface CustomeService {
    public void say();
}

  CustomServiceImpl1:

package com.gjs.service.impl;

import org.springframework.stereotype.Service;

import com.gjs.service.CustomeService;
@Service("service1")
public class CustomServiceImpl1 implements CustomeService {

    @Override
    public void say() {
        System.out.println("CustomerServiceImpl1.say()");
    }
}

  CustomServiceImpl2:

package com.gjs.service.impl;

import org.springframework.stereotype.Service;

import com.gjs.service.CustomeService;

@Service("service2")
public class CustomServiceImpl2 implements CustomeService {

    @Override
    public void say() {
        System.out.println("CustomerServiceImpl2.say()");
    }
}

  CustomController:

package com.gjs.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import com.gjs.service.CustomeService;


@Controller("client")
public class CustomController {
    /*
     * 方式一(推薦) : 在字段(成員變量)上注入
     * @Autowired :
     *     默認會從Spring容器找對應類型的對象注入進來
     *  使用@Autowired 必須保證Spring容器中最少一個類型對應bean ,若是沒有就會拋異常
     *   org.springframework.beans.factory.NoSuchBeanDefinitionException 
     *     可使用 註解的 required屬性(除特殊狀況,通常不使用)
     *  required = true/false 是不是必須有對應的對象,true 是必須有(默認),false 不是必須有
     * 
     *  若是spring容器有多個相同類型的對象,默認沒法注入也會拋異常
     *  org.springframework.beans.factory.NoUniqueBeanDefinitionException 不是惟一的bean異常
     *  這時就須要配合使用 @Qualifier() 註解了
     *  @Qualifier(value="對應bean的id值")能夠在多個相同類型的對象中篩選指定惟一id的對象,「value=」能夠省略
     */
    //@Autowired(required=false)
    //@Qualifier("service1")
    private CustomeService customeService;
    
    /*
     * 方式二 :使用setter方法(屬性)注入
     * 將@Autowired直接貼在set方法上面便可,程序運行,會執行set方法
     * 將Spring容器對應的類型的參數賦值給 set方法的參數,類型不存在或存在多個,處理方式與方式一同樣
     */
    //@Autowired()
    //@Qualifier("service1")
    public void setCustomeService(CustomeService customeService) {
        this.customeService = customeService;
    }
    
    /*
     * 方式三 : 構造器注入
     * 使用註解的IOC建立bean的狀況下
     * 默認bean中有什麼樣的構造器,spring就調用那個構造器去建立對應的bean對象
     * 而且會自動注入 構造器中對應類型參數的對象,無須@Autowired()
     * 
     * 若是構造函數的參數類型對應的bean有多個就在 在參數前面 使用 @Qualifier()註解,指定 對應的bean的id
     */

    public CustomController(@Qualifier("service1")CustomeService customeService) {
        this.customeService = customeService;
    }

    public void say() {
        customeService.say();
    }
    
}

  applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context/spring-context.xsd
">
    <!-- 配置spring要進行掃描的組件註解的包(默認包含子包)的位置 -->
    <context:component-scan base-package="com.gjs"/>
    
</beans>

  測試類TestSpring:

package com.gjs.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.gjs.client.CustomController;

public class TestSpring {
    @Test
    public void testName() throws Exception {
        //1.讀取配置文件,建立Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取調用方 CustomClient對象
        CustomController client = context.getBean("client", CustomController.class);
        //調用CustomClient對象的say()方法
        client.say();
    }
}

  @Resouce

  @Resource 功能等同 @Autowired + @Qualifier
  @Resource只能注入字段和setter方法,不能注入構造方法

  CustomController類,其餘參考上面的

package com.gjs.client;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import com.gjs.service.CustomeService;


@Controller("client")
public class CustomController {
    /*
     * 方式一: 字段注入
     *  也是默認會從Spring容器找對應類型的對象注入進來
     *  有多個相同類型時,可使用@Resource(name="對應bean的id")指定注入哪一個對象
     *  @Resource 必須保證須要注入的類型在Spring容器中最少有一個對象,沒有直接拋異常
     */
    //@Resource(name="service1")
    private CustomeService customeService;
    
    /*
     * 方式二: set方法(屬性)注入
     */
    @Resource(name="service1")
    public void setCustomeService(CustomeService customeService) {
        this.customeService = customeService;
    }
    

    public void say() {
        customeService.say();
    }
    
}

 

  @Value註解

  @Value註解:注入基本數據類型以及它們的包裝類和String類型數據的,支持${}注入Properties文件的鍵值對,等同 <proprty name=」...」 value=」${Key}」>。

@Repository
public class UserDaoImpl implements UserDao {
    
    /**
     * @Value(value="")
     * 能夠從Spring容器讀取 .properties 配置文件內容
     * value :配置文件的對應的key -->使用 ${key} 獲取
     * 程序運行中自動將 properties 對應key的獲取出來設置給字段
     * 
     */
    
    //等價 <property name="driverClassName" value="${jdbc.driverClassName}">
    @Value("${jdbc.driverClassName}") 
    private String driverClassName;
    
    @Value("${jdbc.url}")
    private String url;
    
    @Value("${jdbc.username}")
    private String username;
    
    @Value("${jdbc.password}")
    private String password;
    
    //@Value("${jdbc.maxActive}")
    @Value("10") //開發者也手動賦值
    private String maxActive;
    

    @Override
    public void insert(User user) {
        System.out.println(driverClassName);
        System.out.println(url);
        System.out.println(username);
        System.out.println(password);
        System.out.println(maxActive);

    }

}

  

4.純註解配置

  雖然使用註解的方式,但咱們仍是離不開xml文件,由於咱們還有配置組件掃描位置,若是這也能用註解配置,那麼咱們就能夠脫離xml文件了。
  替換XML配置文件的註解:

  

package com.gjs.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.alibaba.druid.pool.DruidDataSource;

/*
 * @Configuration 
 * 說明把當前類當作成Spring框架的配置文件
 * @ComponentScan 
 *  配置註解包掃描的位置
 * @PropertySource("classpath:db.properties")
 *  讀取.peroperties 後綴的配置文件
 */

@Configuration
@ComponentScan("com.gjs")
@PropertySource("classpath:db.properties")
public class SpringConfig {
    
    
    /**
     * @Value(value="")
     * 能夠從Spring容器讀取 .properties 配置文件內容
     * value :配置文件的對應的key -->使用 ${key} 獲取
     * 程序運行中自動將 properties 對應key的獲取出來設置給字段
     * 
     */
    
    //等價 <property name="driverClassName" value="${jdbc.driverClassName}">
    @Value("${jdbc.driverClassName}") 
    private String driverClassName;
    
    @Value("${jdbc.url}")
    private String url;
    
    @Value("${jdbc.username}")
    private String username;
    
    @Value("${jdbc.password}")
    private String password;
    
    @Value("${jdbc.maxActive}")
    private Integer maxActive;
    
    
    //<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" 
      //init-method="init" destroy-method="close">
    @Bean(name="dataSource",initMethod="init",destroyMethod="close")
    public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(maxActive);
        return dataSource;
    }

}

5. Spring的測試

  5.1.傳統的單元測試

  存在的問題:
    1,每一個測試都要從新啓動Spring容器,啓動容器的開銷大,測試效率低下。
    2,不該該是測試代碼管理Spring容器,應該是Spring容器在管理測試代碼。

  

  5.2 正確的Spring的測試

  

  5.3 如何使用Spring測試

  Spring測試必須保證Eclipse的單元測試的最低版本是 4.12版本,若是使用的Eclipse版本很低,那麼單元測試版本可能低於4.12,那麼須要開發者手動導入單元測試的jar包

  要使用Spring測試就要先導入test的jar包

  

 

 

package com.gjs.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.gjs.client.CustomController;

//表示先啓動Spring容器,把junit運行在Spring容器中
@RunWith(SpringJUnit4ClassRunner.class)
//表示從哪裏加載資源文件,默認從src(源目錄)下面加載
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
    @Test
    public void testName() throws Exception {
        //1.讀取配置文件,建立Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //獲取調用方 CustomClient對象
        CustomController client = context.getBean("client", CustomController.class);
        //調用CustomClient對象的say()方法
        client.say();
    }
}
相關文章
相關標籤/搜索