1. 程式人生 > 其它 >(二)Spring-bean的作用域、xml和註解方式自動裝配以及註解開發

(二)Spring-bean的作用域、xml和註解方式自動裝配以及註解開發

(二)Spring-bean的作用域、xml和註解方式自動裝配以及註解開發

一、 bean的作用域

1.1 定義

當您建立一個 bean 定義時,您建立了一個用於建立由該 bean 定義定義的類的實際例項的方法。bean 定義是一個配方的想法很重要,因為這意味著,與一個類一樣,您可以從一個配方建立許多物件例項。

  • 您不僅可以控制要插入到從特定 bean 定義建立的物件中的各種依賴項和配置值,還可以控制從特定 bean 定義建立的物件的範圍。

  • 這種方法功能強大且靈活,因為您可以通過配置選擇您建立的物件的範圍,而不必在 Java 類級別定義物件的範圍。可以將 Bean 定義為部署在多個範圍之一中。Spring 框架支援六個範圍,其中四個僅在您使用 web-aware 時可用ApplicationContext

    。您還可以建立 自定義範圍。

1.2 六個作用域

Scope Description
singleton (Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype Scopes a single bean definition to any number of object instances.
request Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext
.
session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

1 單例模式

spring預設機制

<bean id="accountService" class="com.something.DefaultAccountService"/>

<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>

2 原型模式

每次從容器get的時候,都會產生一個新的物件!

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

3 其餘的request,session,application

這些個只能在web 開發中使用的。

二、bean使用xml自動裝配

2.1 定義

  • bean裝配是spring滿足bean依賴的一種方式!
  • spring會在上下文中自動尋找,並自動給bean裝配屬性!

2.2 spring中3種裝配方式

  1. 在xml中顯示的配置
  2. 在java中顯示配置
  3. 隱式的自動裝配bean【重要】

2.3 手動裝配VS自動裝配

2.3.1 手動裝配

package com.happy.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor@AllArgsConstructor
public class People {

    private String name;
    private Dog dog;
    private Cat cat;
}

package com.happy.pojo;

public class Cat {

    public void shout(){
        System.out.println("miao miao~");
    }
}

package com.happy.pojo;

public class Dog {
    public void shout(){
        System.out.println("wong wong ~");
    }
}

<?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="dog" class="com.happy.pojo.Dog"></bean>
    <bean id="cat" class="com.happy.pojo.Cat"></bean>
    <bean id="people" class="com.happy.pojo.People">
        <property name="name" value="happy"></property>
        <property name="dog" ref="dog"></property>
        <property name="cat" ref="cat"></property>
    </bean>
</beans>

測試使用

package com.happy.service;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.happy.pojo.People;
public class PeoPleService {


    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        People people = context.getBean("people", People.class);
        System.out.println(people);
        people.getDog().shout();
    }
}

2.3.2 自動裝配

1 ByName

注意:Byname是要保證,待裝配物件的set方法和beanid一致,而並非待裝配物件的屬性名。

package com.happy.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


public class People {

    private String name;
    private Dog dog1;
    private Cat cat;

    public String getName() {
        return name;
    }

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

    public Dog getDog() {
        return dog1;
    }

    public void setDog(Dog dog) {
        this.dog1 = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }


    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", dog1=" + dog1 +
                ", cat=" + cat +
                '}';
    }
}

<?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="dog" class="com.happy.pojo.Dog"></bean>
    <bean id="cat" class="com.happy.pojo.Cat"></bean>

<!--    ByName:會自動在容器上下文中查詢,和自己物件set方法後面的值對應的bean-id-->
    <bean id="people" class="com.happy.pojo.People" autowire="byName">
    </bean>
</beans>
2 ByType

注意:

  • byType有自己的弊端,必須待裝配物件的屬性的型別保證在上下文裡唯一
  • byType的依賴屬性可以不用id都可以。
<?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="dog" class="com.happy.pojo.Dog"></bean>
    <bean class="com.happy.pojo.Cat"></bean>

    <!--    ByType:會自動在容器上下文中查詢,和自己物件屬性型別相同的bean-id-->
    <bean id="people" class="com.happy.pojo.People" autowire="byType">

    </bean>
</beans>

2.4 總結

  • byName的時候,需要保證所有bean的id唯一,並且這bean需要和自動注入的set方法後面的名字一致。
  • byType的時候,需要保證所有bean的class唯一,並且這bean需要和自動注入屬性的型別一致。

三、bean使用註解自動裝配

3.1 使用條件

前提:

  • 和xml一樣,所有依賴的型別都必須在xml即context中有了。

  • jdk1.5,spring2.5以後支援註解。

匯入約束和註解支援<context:annotation-config/>

要使用註解須知:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

實現如下:

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


    <bean id="dog" class="com.happy.pojo.Dog"></bean>
    <bean id="cat" class="com.happy.pojo.Cat"></bean>

    <bean id="people" class="com.happy.pojo.People"></bean>
</beans>

3.2 @Autowired

  • 直接在屬性上使用即可,可以在屬性和set方法上注入,相當於xml得到property

  • 使用Autowired我們可以不用編寫set方法了,前提是你這個自動裝配的屬性已經在IOC容器中存在,且符合按照ByType注入。

  • 先按照type找相同型別的bean注入,如果容器中存在兩個以上相同的,再按照set後面的name進行注入。即先ByType再ByName

  • 如果ByType再ByName都存在兩個以上(ByName沒有找到相同的),則需要使用@Qualifier

3.3 @Qualifier

  • 自動裝配屬性的時候,在容器中存在兩個相同的type能匹配上,又不能匹配name,則需要使用這個註解。
  • 即如果自動裝配的環境比較複雜,自動裝配無法通過一個註解@Autowired完成的時候,我們可以通過Autowired和Qualifier配合使用,就能指定一個唯一的bean物件注入
package com.happy.pojo;


import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;


public class People {


    private String name;
    @Autowired
    @Qualifier(value = "dog2")
    private Dog dog;
    @Autowired
    private Cat cat;

    public String getName() {
        return name;
    }

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

    @NotNull
    public Dog getDog() {
        return dog;
    }
    @Nullable
    public void setDog(@NotNull Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }


    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", dog=" + dog +
                ", cat=" + cat +
                '}';
    }
}

3.4 @Resource

@Resource=@Autowired+@Qualifer

package com.happy.pojo;


import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import javax.annotation.Resource;


public class People {


    private String name;
    //    @Autowired
//    @Qualifier(value = "dog2")
    @Resource(name = "dog2")
    private Dog dog;
    @Autowired
    private Cat cat;

    public String getName() {
        return name;
    }

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

    @NotNull
    public Dog getDog() {
        return dog;
    }

    @Nullable
    public void setDog(@NotNull Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }


    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", dog=" + dog +
                ", cat=" + cat +
                '}';
    }
}

3.5 Autowired vs @Resource

Autowired Resource
相同點 自動裝配 自動裝配
不同點 先type後name 先name後type

四、使用註解開發

4.1 使用條件

  • 在Spring4之後,要使用註解開發,必須要保證aop的包匯入了。
  • 使用註解還需要匯入context名稱空間和約束,增加註解的支援!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.happy.pojo"></context:component-scan>
</beans>

匯入約束和註解支援<context:annotation-config/>

  • 註解驅動,加上這個就可以使用resource這些註解了

匯入包掃描標籤</context:component-scan>

  • 掃描包
  • 配置該標籤後,如果除了這個包沒有在其他地方註解了,就不需要再配置context:annotation-config

4.2 bean

4.2.1 @Component

  • 將component放在類上,說明這個類被Spring 容器管理了,這就是bean。
  • 相當於<bean id="user" class="com.happy.pojo.User"></bean>
package com.happy.pojo;

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

/*<!--   <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@Component
public class User {

    public String name ="高興";

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

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        User user = context.getBean("user",User.class);
        System.out.println(user);
    }
}

4.3 屬性如何注入

4.3.1 @Value

  • @value注入可以不用set方法
  • 相當於<property name="name" value="happybyxml"></property>
  • 複雜型別,如map,list等還是建議用xml注入屬性,而不用註解
package com.happy.pojo;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/*<!--   <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@Component
public class User {

    @Value("happy518")
    public String name ;

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

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        User user = context.getBean("user",User.class);
        System.out.println(user);
    }
}

4.3 衍生的註解

  • @Component有幾個衍生註解,我們再web開發中,會按照mvc三層架構分層。
  • 這3個註解和@Component是等價的,人為定義@Component以後是註解非這3個註解的bean上

4.3.1 Dao層->@Repository

package com.happy.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
}

4.3.2 Service層->@Service

package com.happy.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
}

4.3.3 Controller層->@Controller

package com.happy.controller;

import org.springframework.stereotype.Controller;

@Controller
public class UserController {
}

4.4 自動裝配置

見第三章節。

4.5 作用域

@Scope

package com.happy.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

/*<!--   <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
//@Scope("singleton")
@Scope("prototype")
public class User {

    @Value("happy518")
    public String name ;

}
package com.happy;

import com.happy.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {
    
    @Test
    public void test() {
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
//        單例模式,每次get為同一個物件
        User user1 = context.getBean("user", User.class);
        User user2 = context.getBean("user", User.class);
        System.out.println(user1 == user2);
    }

}

4.6 小結

XML vs 註解

Xml 註解
不同 xml更加萬能,適用於任何場合! 註解:不是自己類使用不了
集中管理,維護簡單 維護相對複雜
解耦 耦合較強

最佳實踐:

  • xml用來管理bean
  • 註解負責完成屬性注入
  • 我們再使用的過程中,只需要注意一個問題,必須要讓註解生效,必須開啟註解的支援

五、使用Java配置類

  • 使用java的方式配置spring,完全不用xml配置了,全權交給java來做

  • JavaConfig是Spring的一個子專案,在Spring 4之後,它成為另一個核心功能。

5.1 @Configuration介紹

1 使用和註冊配置類

  • 在類上加上這個註解,代表該類是一個spring的配置類,等價於一個beans的application-context.xml檔案。

  • 會被spring容器託管,註冊到容器中,因為他本身也是一個component。

2 使用配置類註冊bean

  • 註冊一個bean,就相當於我們之前寫的一個bean標籤
  • 配置類中的方法名字,就相當於bean標籤中的id屬性。
  • 這個方法的返回型別,就相當於bean標籤中的class屬性。
  • 方法的返回物件就是要注入bean的物件

3 獲取容器

  • 完全使用了配置類方式去做的方式,我們需要通過ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class)來獲取容器了。

5.2 配置類使用步驟

1 實體類

package com.happy.pojo;

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

@Data
public class User {
    @Value("gaoxing")
    private String name;

}

2 配置類:

package com.happy.config;

import com.happy.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
//@Component
//@ComponentScan("com.happy.pojo")
public class MyConfig {

    @Bean
    public User getUser(){
        return new User();
    }
}

3 測試類

package com.happy;

import com.happy.config.MyConfig;
import com.happy.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {

    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = (User) context.getBean("getUser");
        System.out.println(user);
    }
}

這種純java的配置方式,在SpringBoot中隨處可見!