前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring学习一、组件注册

Spring学习一、组件注册

作者头像
梅花
发布2020-09-28 11:19:47
5930
发布2020-09-28 11:19:47
举报
文章被收录于专栏:梅花的学习记录

Spring 组件注册的方式

目录

  • Spring 组件注册的方式
    • 1.XML-based metadata
      • 1.1 XML Configuration
      • 1.2 Using the Container
    • 2.Annotation-based Configuration
      • 2.1 Use Configuration Annotated
      • 2.2 Bootstrapping @Configuration classes
      • 2.3 使用CompentScan 扫描
      • 2.4 @compentScan 配置过滤扫描
      • 2.5 @Scope 配置Bean的作用域
      • 2.6 @Lazy 配置懒加载
      • 2.7 @Conditional 条件配置
      • 2.8 @Import导入组件使用
        • 2.8.1@Import 导入所需组件
        • 2.8.2 ImportSelector 导入组件
        • 2.8.3ImportBeanDefinitationRegistrar
      • 2.9 使用FactoryBean注册组件

1.XML-based metadata

1.1 XML Configuration

services.xml

代码语言:javascript
复制
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- services -->
    <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
        <property name="accountDao" ref="accountDao"/>
        <property name="itemDao" ref="itemDao"/>
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for services go here -->

</beans>

The id attribute is a string that identifies the individual bean definition.

The class attribute defines the type of the bean and uses the fully qualified classname.

daos.xml

代码语言:javascript
复制
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="accountDao"
        class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
        <!-- additional collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions for data access objects go here -->

</beans>

1.2 Using the Container

代码语言:javascript
复制
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

2.Annotation-based Configuration

Spring 2.5 introduced support for annotaion-based configruation metadata.

XML-based configuration metadata configures these beans as elements inside a top-level element. Java configuration typically uses @Bean - annotated methods with a Configuration classs.

2.1 Use Configuration Annotated

代码语言:javascript
复制
 @Configuration
 public class AppConfig {

     @Bean
     public MyBean myBean() {
         // instantiate, configure and return bean ...
     }
 }

2.2 Bootstrapping @Configuration classes

代码语言:javascript
复制
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class);
ctx.refresh();
MyBean myBean = ctx.getBean(MyBean.class);

2.3 使用CompentScan 扫描

代码语言:javascript
复制
	/**
	 * Alias for {@link #basePackages}.
	 * <p>Allows for more concise annotation declarations if no other attributes
	 * are needed &mdash; for example, {@code @ComponentScan("org.my.pkg")}
	 * instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
	 */
	@AliasFor("basePackages")
	String[] value() default {};

上面是@CompentScan源码中的value说明,如果给默认值,就相当于扫描basePackages.

代码语言:javascript
复制
@ComponentScan(
        // 配置扫描包的根路径
        value = {"com.zuoyan"}
)

2.4 @compentScan 配置过滤扫描

代码语言:javascript
复制
	/**
	 * Specifies which types are not eligible for component scanning.
	   指定那些类型不适合进行组件扫描
	   
	   需要指定的是一个Filter数组
	 * @see #resourcePattern
	 */
	Filter[] excludeFilters() default {};
代码语言:javascript
复制
	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {

		/**
		 * The type of filter to use.
		 * 指定FilterType 使用的类型
		 */
		FilterType type() default FilterType.ANNOTATION;

		/**
		 * Alias for {@link #classes}.
		 * @see #classes
		 */
		@AliasFor("classes")
		Class<?>[] value() default {};

		
		@AliasFor("value")
		Class<?>[] classes() default {};

		
		String[] pattern() default {};

	}

FilterType 类型

代码语言:javascript
复制
public enum FilterType {

	/**
	 * Filter candidates marked with a given annotation.
	 * @see org.springframework.core.type.filter.AnnotationTypeFilter
	 */
	ANNOTATION,

	/**
	 * Filter candidates assignable to a given type.
	 * @see org.springframework.core.type.filter.AssignableTypeFilter
	 */
	ASSIGNABLE_TYPE,

	/**
	 * Filter candidates matching a given AspectJ type pattern expression.
	 * @see org.springframework.core.type.filter.AspectJTypeFilter
	 */
	ASPECTJ,

	/**
	 * Filter candidates matching a given regex pattern.
	 * @see org.springframework.core.type.filter.RegexPatternTypeFilter
	 */
	REGEX,

	/** Filter candidates using a given custom
	 * {@link org.springframework.core.type.filter.TypeFilter} implementation.
	 */
	CUSTOM

}

使用过滤

代码语言:javascript
复制
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;

import com.atguigu.bean.Person;

//配置类==配置文件
@Configuration  //告诉Spring这是一个配置类

@ComponentScans(
		value = {
				@ComponentScan(value="com.atguigu",includeFilters = 
                               {
						/*						
						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),
						*/
						@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
							},
                    useDefaultFilters = false)
				}
		)
//@ComponentScan  value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class MainConfig {
	
	//给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
	@Bean("person")
	public Person person01(){
		return new Person("lisi", 20);
	}

}

2.5 @Scope 配置Bean的作用域

代码语言:javascript
复制
@Configuration
public class StudentBeanConfiguration {

    @Scope("prototype")
    @Bean
    Student student(){
        return new Student(10001L, "zuoyan");
    }
}
代码语言:javascript
复制
  @Test
    public void testBeanScope(){

        Student stu1 = (Student) applicationContext.getBean("student");
        Student stu2 = (Student) applicationContext.getBean("student");
        System.out.println(stu1 == stu2);
    }

输出结果

代码语言:javascript
复制
Spring Contation Initializer Ok ... 
Student Construct is exec ... 
Student Construct is exec ... 
false

可以看到创建了两次对象,而且两个对象不相等,因为这个是使用的多例的Bean作用域

更改bean的作用域

代码语言:javascript
复制
@Scope("singleton")

还是上面的代码查看控制台输出结果

代码语言:javascript
复制
Student Construct is exec ... 
Spring Contation Initializer Ok ... 
true

2.6 @Lazy 配置懒加载

代码语言:javascript
复制
@Configuration
public class StudentBeanConfiguration {

    @Scope("singleton")
    @Lazy
    @Bean
    Student student(){
        return new Student(10001L, "zuoyan");
    }
}

控制台输出内容

代码语言:javascript
复制
Spring Contation Initializer Ok ... 
Student Construct is exec ... 
true

可以通过和上面的控制台输出内容进行对比,发现Student的构造函数打印在 Spring Container 初始化完成之后调用的,这说明 Bean是在我们需要使用的时候才执行从初始化的。

2.7 @Conditional 条件配置

It is often useful to conditionally enable or disable a complete @Configuration class or even individual @Bean methods, based on some arbitrary system state. One common example of this is to use the @Profile annotation to activate beans only when a specific profile has been enabled in the Spring Environment (see Bean Definition Profiles for details).

大意就是条件注解对一个类或者独立的Bean注册方法的启用或者禁用非常有帮助,一个最常见的例子就是使用@Profile注解指定一个特定的配置文件来激活Bean

在需要添加的配置类上添加条件注解,控制粒度可以具体到某个方法上

代码语言:javascript
复制
@Conditional({SystemOSCondition.class})
@Configuration
public class StudentBeanConfiguration {

    @Scope("singleton")
    @Lazy
    @Bean
    Student student(){
        return new Student(10001L, "zuoyan");
    }


    @Bean
    Student windows(){
        return new Student(00001L, "Windows");
    }
    
    @Bean
    Student linux(){
        return new Student(00002L, "Windows");
    }
}

需要自己实现Spring-Framework 中的Condition接口

代码语言:javascript
复制
/**
 * @Author: ZuoYanCoder
 * @Description: 实现自定义的条件
 * @Date: 2020/4/17 10:50
 * @Version: 1.0
 */
public class SystemOSCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Environment environment = context.getEnvironment();
        String systemOsNanme = environment.getProperty("os.name");
        System.out.println(systemOsNanme);
        return systemOsNanme.contains("Windows");
    }
}

测试方法代码类

代码语言:javascript
复制
@Test
    public void testConditionalAnnotated(){

        String[] beanNamesForType = applicationContext.getBeanNamesForType(Student.class);

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

        Map<String, Student> studentMap = applicationContext.getBeansOfType(Student.class);

        System.out.println(studentMap);
    }

执行测试方法打印结果

代码语言:javascript
复制
Windows 10
Windows 10
Windows 10
Student Construct is exec ... 
Student Construct is exec ... 
Spring Contation Initializer Ok ... 
student
windows
linux
Student Construct is exec ... 
{student=Student{stuId=10001, name='zuoyan'}, windows=Student{stuId=1, name='Windows'}, linux=Student{stuId=2, name='Windows'}}

配置IDEA 运行时环境变量

代码语言:javascript
复制
-Dos.name=Linux

然后在运行打印结果

代码语言:javascript
复制
Linux
Spring Contation Initializer Ok ... 
{}

2.8 @Import导入组件使用

2.8.1@Import 导入所需组件

首先通过代码打印输出Spring容器中有的组件

代码语言:javascript
复制
@Test
    public void testImportAnnotation(){

        String[] names = applicationContext.getBeanDefinitionNames();

        for (String name: names) {
            System.out.println(name);

        }

    }

控制台输出

代码语言:javascript
复制
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
studentBeanConfiguration
student
windows
linux

通过使用@Import导入需要的组件

代码语言:javascript
复制
@Conditional({SystemOSCondition.class})
@Configuration
@Import({Animal.class})
public class StudentBeanConfiguration {
}

控制台输出

代码语言:javascript
复制
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
studentBeanConfiguration
com.zuoyan.bean.Animal
student
windows
linux

@Import可以导入多个类,默认的id是类的全路径

2.8.2 ImportSelector 导入组件
代码语言:javascript
复制
@Conditional({SystemOSCondition.class})
@Configuration
@Import({Animal.class, MyImportSelector.class})
public class StudentBeanConfiguration {}

MyImportSelector类的内容

代码语言:javascript
复制
public class MyImportSelector implements ImportSelector {

    /**
     *  方法返回值就是类的全路径名的数组
     *
     * @param importingClassMetadata  可以获取标有Import注解类的的所有注解
     *
     * @return
     */
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

		// 方法可以返回空字符串数组,但是不能返回Null
        return new String[]{"com.zuoyan.bean.Cat","com.zuoyan.bean.Dog"};
    }
}

控制台打印输出

代码语言:javascript
复制
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
studentBeanConfiguration
com.zuoyan.bean.Animal
com.zuoyan.bean.Cat
com.zuoyan.bean.Dog
student
windows
linux

可以看到需要导入的组件已经导入到容器之中了。

2.8.3ImportBeanDefinitationRegistrar

在配置类上添加 ImportBeanDefinitationRegistrar

代码语言:javascript
复制
@Conditional({SystemOSCondition.class})
@Configuration
@Import({Animal.class, MyImportSelector.class, MyImportBeanDefinitationRegister.class})
public class StudentBeanConfiguration {}

MyImportBeanDefinitationRegister实现

代码语言:javascript
复制
public class MyImportBeanDefinitationRegister implements ImportBeanDefinitionRegistrar {

    /**
     *
     * @param importingClassMetadata  当前类的所有注解信息
     * @param registry BeanDefinition注册类,把所有需要添加的组件注册到容器中
     *                 调用BeanDefinitionRegistry.registerBeanDefinition手工注册来
     *
     */

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
        boolean catFlag = registry.containsBeanDefinition("com.zuoyan.bean.Cat");
        boolean dogFlag = registry.containsBeanDefinition("com.zuoyan.bean.Dog");

        if(catFlag && dogFlag)
        {

            // 指定Bean的定义信息
            RootBeanDefinition beanDefinition = new RootBeanDefinition(Elephant.class);
            // 指定注册Bean的名称
            registry.registerBeanDefinition("Elephant",beanDefinition);

        }
    }
}

测试类

代码语言:javascript
复制
    @Test
    public void testImportAnnotation(){

        String[] names = applicationContext.getBeanDefinitionNames();

        for (String name: names) {
            System.out.println(name);

        }

    }

控制台打印输出

代码语言:javascript
复制
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
studentBeanConfiguration
com.zuoyan.bean.Animal
com.zuoyan.bean.Cat
com.zuoyan.bean.Dog
student
windows
linux
Elephant

2.9 使用FactoryBean注册组件

首先通过自己定义一个类然后实现BeanFactory的接口

代码语言:javascript
复制
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;

/**
 * @Author: ZuoYanCoder
 * @Description:
 * @Date: 2020/4/23 14:17
 * @Version: 1.0
 */
public class CarFactoryBean implements FactoryBean<JeepCar> {


    /**
     *  需要管理的对象
     * @return
     * @throws Exception
     */
    @Nullable
    public JeepCar getObject() throws Exception {
        return new JeepCar();
    }

    /**
     * 返回类的类型
     * @return
     */
    @Nullable
    public Class<?> getObjectType() {
        return JeepCar.class;
    }

    /**
     * 是否为单例模式
     * @return
     */
    public boolean isSingleton() {
        return false;
    }
}

然后在配置中将注入进去

代码语言:javascript
复制
    @Bean
    CarFactoryBean carFactoryBean(){
        return new CarFactoryBean();
    }

通过测试

代码语言:javascript
复制
 /**
     * 通过对象工程类管理对象
     */
    @Test
    public void testBeanFactory(){
        Object carFactoryBean = applicationContext.getBean("carFactoryBean");
        System.out.println("获取Bean的类型是:" + carFactoryBean.getClass());
}

查看获取到的对象是

代码语言:javascript
复制
获取Bean的类型是:class com.zuoyan.bean.JeepCar

如果需要获取工厂类对象需要在前面加上 & 符号

代码语言:javascript
复制
获取Bean的类型是:class com.zuoyan.bean.CarFactoryBean

通过isSingleton() 方法可以设置放进容器的对象是单例还是多例。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring 组件注册的方式
    • 1.XML-based metadata
      • 1.1 XML Configuration
      • 1.2 Using the Container
    • 2.Annotation-based Configuration
      • 2.1 Use Configuration Annotated
      • 2.2 Bootstrapping @Configuration classes
      • 2.3 使用CompentScan 扫描
      • 2.4 @compentScan 配置过滤扫描
      • 2.5 @Scope 配置Bean的作用域
      • 2.6 @Lazy 配置懒加载
      • 2.7 @Conditional 条件配置
      • 2.8 @Import导入组件使用
      • 2.9 使用FactoryBean注册组件
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档