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是错误的

posted @ 2022-03-06 14:33  liwl1991  阅读(1442)  评论(0编辑  收藏  举报