Spring通過註解批量註冊bean

本篇博客主要參考了【路人甲Java】系列博文的《Spring高手系列》的學習指導思路,進行的編碼和測試。

本文最後更新於:2022年03月06日

1. 引言

Srping時bean的管理容器。批量註冊bean是Spring的基本操作。

Spring批量註冊bean的方式有2種:

  • @ComponentScan和@ComponentScans
  • @Import

2. @ComponentScan(s)批量註冊

2.1 @ComponentScan

@ComponentScan用於批量註冊bean。該註解會讓spring去掃描【某些包以及其子包內的所有的類】,然後【將滿足一定條件的類作爲bean】註冊到容器中。

從這句話可以看出幾個重點:

  • @ComponentScan掃描的是包,子包裏面的所有類。這就需要確認掃描哪些包。確認包的方式有兩種:
    • 按照包名。也就是指定直接確認包名。
    • 按照類名。也就是通過類名來間接確認包名。
  • 將滿足一定調節的類作爲bean註冊到容器。這就需要通過某些調節來確認目標bean:
    • useDefaultFilters默認過濾。有某些註解的類,可以作爲bean註冊。比如:@Component,@Controller,@Service,@Repository
    • includeFilters白名單過濾。
    • excludeFilters黑名單過濾。

@ComponentScan可以通過value或者basePackage來配置要掃描的包。通過value掃描時,使用方法如下:

@ComponentScan({"package01","package02"})

這樣就可以把package01和package02包內的類註冊爲bean。

注意:通過這樣指定包名掃描,有一個隱患:若包被重命名了,會導致掃描失效。

所以一般情況下,我們使用basePackageClasses的方式來指定掃描的包,該參數可以指定一些類型,默認會掃描這些類所在的包及其子包中所有的類,這種方式可以有效避免這種問題。

2.2 @includeFilters

2.2.1 掃描包含註解的類

如上所述,該註解通過一個Filter類型的數組,存放要被掃描的類。它作爲@CompoentScan的一個參數使用。

使用方法如下:

@ComponentScan(
    useDefaultFilters = false; //默認是true
    includeFilters = {
        @ComponentScan.Filter(type=FilterType.ANNOTATION,classes=自定義註解)
    }
)

通過includeFilters可以註冊自定義註解。但是這種自定義註解無法指定bean的名稱。

通過對自定義註解的改造,可以完成自定義bean能夠指定bean的名稱。

2.2.2 包含指定類型的類

使用方法如下:

@ComponentScan(
    useDefaultFilters = false; //默認是true
    includeFilters = {
        @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes=自定義類型.class)
    }
)

這樣,被掃描的滿足【自定義類型.class.isAssignableFrom】條件的都會被註冊

2.3 自定義Filter

2.3 練習代碼

源碼目錄:/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev

  • Person.Java 接口
  • PersonImpl.java 實現類
  • School.java 接口
  • SchoolImpl.java 實現類
  • SpringConfig.java 配置類

測試目錄:/root/liwldev/java/web/springframe/SpringAnnotation/src/test/java/com/liwl/dev

  • MyTest.java

其他:

  • 刪除bean.xml,完全使用註解來配置
  • 保留all.properties外部屬性配置文件

2.3.1 @ComponentScan註解和@Component註解

這小節練習@Component註解。

使用該註解的類都會註冊到spring裏面,bean的名稱需要通過@Component(value = "bean名稱")來指定。如果不指定,則是以【首字母小寫的類名】作爲bean的名稱。

PersonImpl.java

package com.liwl.dev;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;


@PropertySource(value = {"classpath:all.properties"},encoding = "utf-8")
@Component
public class PersonImpl implements Person {
    

    @Value(value = "${liwl_name}")
    private String name;
    @Value(value = "${liwl_age}")
    private int age;
    @Autowired
    private School school; //這裏沒有使用@Qualifier註解

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }


    @Override
    public String toString() {
        return "PersonImpl->" + "name:" + name + ",age:" + age + ",school:" + school;
    }
}

SchoolImpl.java

package com.liwl.dev;

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

@Component
public class SchoolImpl implements School {

    @Value(value = "${school_name}")
    private String name;
    @Value(value = "${school_address}")
    private String address;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "SchoolImpl->" + "name:" + name + ",address:" + address;
    }
}

SpringConfig.java

package com.liwl.dev;

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

@Configuration
@ComponentScan
public class SpringConfig {
    public void showMe(){
        System.out.println("我是配置類的showMe方法");
    }
}

MyTest.java代碼

package com.liwl.dev;

import java.util.Arrays;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        for(String beanName: context.getBeanDefinitionNames()){
            String[] aliases = context.getAliases(beanName);
            System.out.println(String.format("bean名稱:%s,別名:%s,bean對象:%s", beanName,Arrays.asList(aliases),context.getBean(beanName)));
        }
        ((ConfigurableApplicationContext) context).close();
    }
}

F5運行MyTest.java結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$60335662@65c7a252
bean名稱:personImpl,別名:[],bean對象:PersonImpl->name:"liwl",age:30,school:SchoolImpl->name:"江南",address:"無錫"
bean名稱:schoolImpl,別名:[],bean對象:SchoolImpl->name:"江南",address:"無錫"

然後@Component通過value設置bean名稱

//代碼片段
@Component(value = "liwl")
public class PersonImpl implements Person {
    ...;
}
//SchoolImpl.java代碼片段
@Component(value = "school")
public class SchoolImpl implements School {
    ...;
}

F5運行MyTest.java結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$60335662@65c7a252
bean名稱:liwl,別名:[],bean對象:PersonImpl->name:"liwl",age:30,school:SchoolImpl->name:"江南",address:"無錫"
bean名稱:school,別名:[],bean對象:SchoolImpl->name:"江南",address:"無錫"

可以看到bean名稱已經對應設置。

這裏有個奇怪的問題:

PersonImpl.java裏面,PersonImpl對School依賴時,直接通過@Autowired使得School類型bean自動注入即可,不需要@Qualifiler,加上也無妨。這個跟之前一個練習試驗不一樣。記錄於2022年03月02日。

2.3.2 @ComponentScan註解和@Controller,@Service,@Repository

@Controller,@Service,@Respository這三個註解實際上區別不大。只是在代碼框架邏輯上進行的人爲區別。

修改PersonImpl.java代碼,把註解@Component換成@Controller

package com.liwl.dev;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;


@PropertySource(value = {"classpath:all.properties"},encoding = "utf-8")
@Controller(value = "liwl")
public class PersonImpl implements Person {
    

    @Value(value = "${liwl_name}")
    private String name;
    @Value(value = "${liwl_age}")
    private int age;
    @Autowired
    @Qualifier(value = "school")
    private School school;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public School getSchool() {
        return school;
    }

    public void setSchool(School school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return "PersonImpl->" + "name:" + name + ",age:" + age + ",school:" + school;
    }
}

修改SchoolImpl.java

package com.liwl.dev;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Service(value = "school")
public class SchoolImpl implements School {

    @Value(value = "${school_name}")
    private String name;
    @Value(value = "${school_address}")
    private String address;

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "SchoolImpl->" + "name:" + name + ",address:" + address;
    }
}

F5運行結果

bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$376ebf8@6340e5f0
bean名稱:liwl,別名:[],bean對象:PersonImpl->name:"liwl",age:30,school:SchoolImpl->name:"江南",address:"無錫"
bean名稱:school,別名:[],bean對象:SchoolImpl->name:"江南",address:"無錫"

總結,上面可以看出實際上被其他註解標註的類,都被當做bean加載到容器裏面,並無區別。

2.3.3 @Component掃描指定的包

在@Component註解源碼能夠看到其被@Repeatable(ComponentScans.class)註解,說明@Component註解能夠同時使用多個。

通過以下三個參數來指定要掃描哪些包:

  • value = String
  • basePackages = String[]
  • basePackageClasses

通過value或者basePackages。value值是字符串,basePackages是字符串數組

通過以下方式來指定要掃描的包

//方式一:
@Component(value = "package")
//方式二:
@Component(basePackages={
	"package001",
    "package002"
})
//方式三:
@Component(basePackageClasses = "自定義類型")

首先在源碼目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev下創建三個目錄

  • controller
    • LiwlController.java
  • service
    • LiwlService.java
  • dao
    • LiwlDao.java

LiwlController.java源碼裏面使用註解@Controller,如下:

package com.liwl.dev.controller;

import org.springframework.stereotype.Controller;

@Controller
public class LiwlController {
    
}

LiwlService.java源碼裏面使用註解@Service,如下:

package com.liwl.dev.service;

import org.springframework.stereotype.Service;

@Service
public class LiwlService {
    
}

LiwlDao.java源碼裏面使用註解@Repository,如下:

package com.liwl.dev.dao;

import org.springframework.stereotype.Repository;

@Repository
public class LiwlDao {
    
}

然後修改SpringConfig.java,採用value參數形式

package com.liwl.dev;


import com.liwl.dev.controller.ScanClassToBean;
import com.liwl.dev.dao.ScanClassToBean01;

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

@Configuration
@ComponentScan(value = "com.liwl.dev")
public class SpringConfig {
}

F5運行MyTest.java結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$6f9fd2da@47af7f3d
bean名稱:liwl,別名:[],bean對象:PersonImpl->name:"liwl",age:30,school:SchoolImpl->name:"江南",address:"無錫"
bean名稱:school,別名:[],bean對象:SchoolImpl->name:"江南",address:"無錫"
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@7c729a55
bean名稱:liwlDao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@3bb9a3ff
bean名稱:liwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@661972b0

修改SpringConfig.java,採用basePackages參數形式

package com.liwl.dev;

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

@Configuration
@ComponentScan(basePackages={
    "com.liwl.dev.controller",
    "com.liwl.dev.service"
})
public class SpringConfig {
    public void showMe(){
        System.out.println("我是配置類的showMe方法");
    }
}

F5運行MyTest.java,結果如下:

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$cec403aa@6cd28fa7
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@614ca7df
bean名稱:liwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@4738a206

可見:

當通過註解@ComponentScan指定要掃描的包時,spring裏面註冊的bean,就是指定包裏面的類對象,以【首字母小寫的類名】作爲bean的名稱。

注意:

指定包名來確認要註冊的bean,存在一個問題。當包名被重命名之後,會導致掃描包失敗。因此一般情況下,使用basePackageClasses的方式來指定要掃描的包。

通過basePackageClasses

使用value或者basePackages來指定要掃描的包時,會因爲包名的變化導致掃描失敗。basePackageClasses的指定方式,能夠解決此類問題。它通過掃描參數指定的類型(自定義類型,接口)所在的包以及其子包中所有的類,來避免包名變化導致無法掃描的問題。

因爲註解@ComponentScan被@Repeatable註解,所以使用basePackageClasses時,必須通過多重註解的方式添加分佈在等級包名下的自定義類型。

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev/controller下創建ScanClassToBean.java

package com.liwl.dev.controller;

public interface ScanClassToBean {
    
}

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev/service下創建ScanClassToBean01.java

package com.liwl.dev.dao;

public interface ScanClassToBean01 {
    
}

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.controller.ScanClassToBean;

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

@Configuration
@ComponentScan(basePackageClasses = ScanClassToBean.class)
public class SpringConfig {
}

F5運行MyTest.java結果如下

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$46d705db@4c9f8c13
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@5ae50ce6

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.controller.ScanClassToBean;
import com.liwl.dev.service.ScanClassToBean01;

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

@Configuration
@ComponentScan(basePackageClasses = ScanClassToBean.class)
@ComponentScan(basePackageClasses = ScanClassToBean01.class)
public class SpringConfig {
}

F5運行MyTest.java結果如下

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$a25f16fb@5bd03f44
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@29626d54
bean名稱:liwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@5a63f509

2.3.4 includeFilters使用

1. 指定包含指定註解的類

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev下創建annotation目錄

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev/annotation下創建LiwlAnnotation.java

package com.liwl.dev.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

public @interface LiwlAnnotation{

}

修改LiwlDao.java

package com.liwl.dev.dao;

import com.liwl.dev.annotation.LiwlAnnotation;

import org.springframework.stereotype.Repository;

@Repository
@LiwlAnnotation
public class LiwlDao {
    
}

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.annotation.LiwlAnnotation;

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

@Configuration
@ComponentScan(
    includeFilters = {
    @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = LiwlAnnotation.class)
})
public class SpringConfig {
}

F5運行MyTest.java結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$f8c8671a@3e58a80e
bean名稱:liwl,別名:[],bean對象:PersonImpl->name:"liwl",age:30,school:SchoolImpl->name:"江南",address:"無錫"
bean名稱:school,別名:[],bean對象:SchoolImpl->name:"江南",address:"無錫"
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@4fb61f4a
bean名稱:liwlDao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@4fb0f2b9
bean名稱:liwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@79924b

從上面運行結果發現,所有類都被註冊爲bean。爲什麼includeFilters參數沒有生效?這是因爲@ComponentScan有一個參數useDefaultFilters,該參數默認是true,修改爲false,再觀察結果。

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.annotation.LiwlAnnotation;

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

@Configuration
@ComponentScan(
    useDefaultFilters = false,
    includeFilters = {
    @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = LiwlAnnotation.class)
})
public class SpringConfig {
}

F5運行MyTest.javaJ結果

....
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$c34b74e6@6a400542
bean名稱:liwlDao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@6580cfdd

從上面運行結果發現,之後標準了註解@LiwlAnnotation的類LiwlDao,纔會被註冊到spring裏面

在上面的自定義註解@LiwlAnnotation裏面,無法自定義bean的名稱。下面通過改造該註解,使其具備自定義bean的功能。

修改LiwlAnnotation.java

package com.liwl.dev.annotation;

import java.lang.annotation.*;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface LiwlAnnotation{
    @AliasFor(annotation = Component.class)
    String value() default "";
}

修改LiwlDao.java

package com.liwl.dev.dao;

import com.liwl.dev.annotation.LiwlAnnotation;

import org.springframework.stereotype.Repository;

@Repository
@LiwlAnnotation(value = "liwldao")
public class LiwlDao {
    
}

F5運行MyTest.java

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$4ba0f5e7@1700915
bean名稱:liwldao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@21de60b4

從運行結果能夠看出,spring已經註冊了名爲liwldao的bean

2. 指定包含指定類型的類

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.service.LiwlService;

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

@Configuration
@ComponentScan(
    useDefaultFilters = false,
    includeFilters = {
    @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = LiwlService.class)
})
public class SpringConfig {
}

F5運行MyTest.java結果如下

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$776b2c0c@c267ef4
bean名稱:liwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@30ee2816

從結果可以看出,spring只註冊了LiwlService的bean。

2.3.5 自定義過濾器

本部分待補充

2.3.6 @ComponentScans重複使用

@ComponentScan在定義中使用了@Repeatable註解,表示該註解可以重複使用。一般使用方式如下:

@ComponentScan(backPacagekClasses = 自定義類型.class)
@ComponentScan(
    useDefaultFilters = false,
    includeFilters = {
        @CompontScan.Filter(type=Filter.Type.ASSIGNABLE_TYPE,classes=自定義類)
    })

或者

@ComponentScans({
    @ComponentScan(backPacagekClasses = 自定義類型.class)
	@ComponentScan(
    useDefaultFilters = false,
    includeFilters = {
        @CompontScan.Filter(type=Filter.Type.ASSIGNABLE_TYPE,classes=自定義類)
    })})

3. @Import

@Import註解跟xml配置的<import>標籤作用一樣,允許通過它引入:

  • @Configuration標註的類
  • ImportSelector接口和ImportBeanDefinitionRegistrar接口實現
  • @Component註解的普通類

總的來說:@Import可以用來批量導入需要註冊的各種類,普通類,配置類,完成bean的註冊。

@Import的參數value常見的5種用法

  • value爲普通的類
  • value爲@Configuration標註的類
  • value爲@ComponetentScan標註的類
  • value爲ImportBeanDefinionRegistart接口類型
  • value爲ImportSelector接口類型
  • value爲DeferredImportSelector接口類型

3.1 value爲普通的類

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.dao.LiwlDao;
import com.liwl.dev.service.LiwlService;

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

@Configuration
@ComponentScan(value = "com.liwl.dev.controller")
public class SpringConfig {
}

修改MyTest.java

package com.liwl.dev;

import java.util.Arrays;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        System.out.println("\n...");
        for(String beanName: context.getBeanDefinitionNames()){
            String[] aliases = context.getAliases(beanName);
            if(beanName.contains("org.springframework")){
                continue;
            }
            System.out.println(String.format("bean名稱:%s,別名:%s,bean對象:%s", beanName,Arrays.asList(aliases),context.getBean(beanName)));
        }
        ((ConfigurableApplicationContext) context).close();
    }
}

修改LiwlService.java和LiwlDao.java,去掉全部在註解,變爲普通類

package com.liwl.dev.dao;

import com.liwl.dev.annotation.LiwlAnnotation;

import org.springframework.stereotype.Repository;

public class LiwlDao {
    
}
package com.liwl.dev.service;

import org.springframework.stereotype.Service;

public class LiwlService {
    
}

F5運行MyTest.java結果如下

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$e5da1911@35047d03
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@49b0b76

從結果可以發現,只有liwlController的bean註冊到了spring容器裏。

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.dao.LiwlDao;
import com.liwl.dev.service.LiwlService;

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

@Configuration
@ComponentScan(value = "com.liwl.dev.controller")
@Import({LiwlService.class,LiwlDao.class})
public class SpringConfig {
}

F5運行MyTest.java結果如下

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$6fa9b108@e056f20
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@4b0b0854
bean名稱:com.liwl.dev.service.LiwlService,別名:[],bean對象:com.liwl.dev.service.LiwlService@19bb07ed
bean名稱:liwldao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@10e41621

從結果可以看出,已經通過@Import註解,向spring容器註冊了普通的類LiwlService和LiwlDao

此時也可以在要被註冊的LiwlService上使用註解@Compoent(value="xxx")的方式,爲bean指定名稱,比如:

修改LiwlService.java

package com.liwl.dev.service;

import org.springframework.stereotype.Service;

@Service(value = "liwlservice")
public class LiwlService {
    
}

F5運行結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$6f60a7f@17046283
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@5bd03f44
bean名稱:liwlservice,別名:[],bean對象:com.liwl.dev.service.LiwlService@29626d54
bean名稱:com.liwl.dev.dao.LiwlDao,別名:[],bean對象:com.liwl.dev.dao.LiwlDao@5a63f509

從運行結果發現,此時已經給LiwlService要註冊的bean,設置了名稱liwlservice

總結:

按照模塊的方式進行導入,需要哪個某塊就導入那個某塊,不需要的時候,直接修改一下總的配置類,調整@Import的value就可以了。

3.2 value爲@Configuration標註的配置類

這種情況主要發生在項目很大時,需要劃分很多模塊,會按照模塊獨立開發,每個某塊在maven中表現爲一個個構建,然後通過座標的方式引入需要引入的模塊。

假如項目中有2個模板,2個模塊都有各自的配置類。

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev下創建config目錄

在config目錄下創建SpringSubConfig01.java和SpringSubConfig02.java文件

修改SpringSubConfig01.java

package com.liwl.dev.config;

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

@Configuration
public class SpringSubConfig01 {

    @Bean(value = "sprintsubconfig01_show")
    public String show(){
        return "我是SpringSubconfig01配置類";
    }
    
}

修改SpringSubConfig02.java

package com.liwl.dev.config;

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

@Configuration
public class SpringSubConfig02 {
    
    @Bean(value = "springsubconfig02_show")
    public String show(){
        return "我是SpringSubConfig02配置類";
    }
}

修改主配置文件SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.config.SpringSubConfig01;
import com.liwl.dev.config.SpringSubConfig02;

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

@Configuration
@Import({SpringSubConfig01.class,SpringSubConfig02.class})
public class SpringConfig {
}

F5運行MyTest.java結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$7afc888b@6193932a
bean名稱:com.liwl.dev.config.SpringSubConfig01,別名:[],bean對象:com.liwl.dev.config.SpringSubConfig01$$EnhancerBySpringCGLIB$$402ae426@647fd8ce
bean名稱:sprintsubconfig01_show,別名:[],bean對象:我是SpringSubconfig01配置類
bean名稱:com.liwl.dev.config.SpringSubConfig02,別名:[],bean對象:com.liwl.dev.config.SpringSubConfig02$$EnhancerBySpringCGLIB$$788d8747@159f197
bean名稱:springsubconfig02_show,別名:[],bean對象:我是SpringSubConfig02配置類

從結果可以看出,2個模塊的子配置類,已經成功導入主配置,並且註冊到spring容器。

3.3 value爲@ComponentScan標註的類

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev/controller下創建LiwlScanClass01.java

package com.liwl.dev.controller;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class LiwlScanClass01 {
    
}

在目錄/root/liwldev/java/web/springframe/SpringAnnotation/src/main/java/com/liwl/dev/service下創建LiwlScanClass02.java

package com.liwl.dev.service;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class LiwlScanClass02 {
    
}

修改SpringConfig.java

package com.liwl.dev;

import com.liwl.dev.controller.LiwlScanClass01;
import com.liwl.dev.service.LiwlScanClass02;

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

@Configuration
@Import({LiwlScanClass01.class,LiwlScanClass02.class})
public class SpringConfig {
}

F5運行結果

...
bean名稱:springConfig,別名:[],bean對象:com.liwl.dev.SpringConfig$$EnhancerBySpringCGLIB$$3a9f6330@29626d54
bean名稱:liwlController,別名:[],bean對象:com.liwl.dev.controller.LiwlController@5a63f509
bean名稱:liwlservice,別名:[],bean對象:com.liwl.dev.service.LiwlService@6e4784bc
bean名稱:com.liwl.dev.controller.LiwlScanClass01,別名:[],bean對象:com.liwl.dev.controller.LiwlScanClass01@34b7ac2f
bean名稱:com.liwl.dev.service.LiwlScanClass02,別名:[],bean對象:com.liwl.dev.service.LiwlScanClass02@e056f20

從運行結果來看,已經成功註冊了了包controller和包service包的類。

目錄下的接口未註冊,並且接口使用@ComponentScan是錯誤的

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