ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring Beans初始化

2021-12-03 22:33:11  阅读:196  来源: 互联网

标签:初始化 ParentRunner java Spring springframework Beans beans org junit


Spring Framework框架中,各个对象都被当为Bean来进行管理,具体由IoC容器来进行初始化、存储及销毁等。

IoC容器内部,这类Bean具体由BeanDefinition来表示,该对象定义了如下信息:

  • 全路径类名
  • Bean的行为特性(如:scope范围、生命周期回调等)
  • Bean的依赖信息
  • 其它配置信息

1. Bean的定义

Spring Framework框架中,每一个Bean都有一个或多个唯一的标识。可以使用传统的XML的形式配置Bean,也可以使用Java Config的形式来配置Bean

XML的元信息配置中,可以使用idname来标识Bean。其中,name可以设置多个值,用,;或空格隔开。不指定idname时,Spring会生成一个默认的标识。

自动生成Bean的唯一标识,遵循Java标准规则,即使用java.beans.Introspector#decapitalize方法,若前两个字母都是大写,则不会变换,否则,将首字母小写

2. 初始化Bean

Bean的初始化主要有以下三种方式:

  • 构造方法
  • 静态工厂方法
  • 工厂方法

首先,来看构造器初始化的方式
新建maven工程,并引入Spring Framework相关依赖,如下:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <springFramework.version>5.2.0.RELEASE</springFramework.version>
    </properties>

     <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${springFramework.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
                <scope>test</scope>
            </dependency>
     </dependencies>

引入spring-context模块实际会引入Spring Framework好几个模块,如:spring-corespring-beansspring-aopspring-expression等。

2.1 构造器方式

首先来看XML的形式,创建一个普通的PoJo对象,如下:

package com.vielat.springframework.bean.service;

/**
 * TODO
 *
 * @author Michael
 * @since 2021/12/3
 */
public class ConstructorClientService {

}

src/main/resources目录下新建META-INF/applicationContext.xml文件,内容如下:

<?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="service" class="com.vielat.springframework.bean.service.ConstructorClientService" />

</beans>

src/test/java目录下编写Junit测试类,如下:

public class XmlApplicationDemo {

    @Test
    public void testConstructorInitializing(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
        System.out.println(ac.getBean("service"));
    }
}

运行Junit测试类后,执行结果如下:


com.vielat.springframework.bean.service.ConstructorClientService@77ec78b9

Process finished with exit code 0

若为该PoJo添加有参的构造函数,如下:

public class ConstructorClientService {

    public ConstructorClientService(String name){

    }
}

再次执行Junit测试类,则会抛出如下异常:

十二月 03, 2021 7:57:00 上午 org.springframework.context.support.AbstractApplicationContext refresh
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service' defined in class path resource [META-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.vielat.springframework.bean.service.ConstructorClientService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.vielat.springframework.bean.service.ConstructorClientService.<init>()

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'service' defined in class path resource [META-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.vielat.springframework.bean.service.ConstructorClientService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.vielat.springframework.bean.service.ConstructorClientService.<init>()

	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
	at com.vielat.springframework.bean.XmlApplicationDemo.testConstructorInitializing(XmlApplicationDemo.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.vielat.springframework.bean.service.ConstructorClientService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.vielat.springframework.bean.service.ConstructorClientService.<init>()
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312)
	... 38 more
Caused by: java.lang.NoSuchMethodException: com.vielat.springframework.bean.service.ConstructorClientService.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
	... 39 more

由上述日志可以看到,在XML中的bean标签若只配置id和class属性(其中id属性可以省略),会直接使用class对应对象的无参构造器进行初始化,若该对象没有提供无参构造器,则会抛出异常。若想使用带参数的构造器进行初始化,需要在XML配置中进行相应的配置,如下:

...
  <bean id="service" class="com.vielat.springframework.bean.service.ConstructorClientService">
        <constructor-arg name="name" value="Michael" />
  </bean>

上述配置,除了使用name字段属性,还可以使用index下标的方式进行指定。
除此之外,在Spring Framework 3.1之后,还提供一种更加简化的命名空间的形式,如下:

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="service" class="com.vielat.springframework.bean.service.ConstructorClientService">
        <constructor-arg name="name" value="Michael" />
    </bean>

    <bean id="service2" class="com.vielat.springframework.bean.service.ConstructorClientService" c:name="Michael">
    </bean>

</beans>

需要在beans签名上新增xmlns:c="http://www.springframework.org/schema/c",在指定构造参数时可以直接配置为c:属性名的形式。

2.2 静态工厂方式

编写一个静态工厂类,如下:

public class ClientService {

    private static final ClientService service = new ClientService();

    public static ClientService getInstance() {
        return service;
    }

    public ClientService getService(){
        return service;
    }
}

XML配置信息如下:

 <bean name="clientService" class="com.vielat.springframework.bean.service.ClientService" factory-method="getInstance" />

测试类如下:

    @Test
    public void testStaticFactoryInitializing(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("META-INF/application.xml");
        System.out.println(ac.getBean("clientService"));
    }

2.3 工厂方法

与静态工厂方法类似,也是通过FactoryBean来初始化对象,只不过初始化方法没有static进行修饰。
工厂方法定义如下:

public class DefaultServiceLocator {
    public ClientService createClientService() {
        return new ClientService();
    }
}

XML定义如下:

  <bean id="defaultServiceLocator" class="com.vielat.springframework.bean.service.DefaultServiceLocator"/>
  <bean id="serviceLocator" factory-bean="defaultServiceLocator" factory-method="createClientService" />

测试类如下:

    @Test
    public void testFactoryInitializing() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
        System.out.println(ac.getBean("serviceLocator"));
    }

无论是静态工厂还是普通工厂类,均可以初始化多个Bean,只需在工厂类中定义多个方法即可,代码略。这类工厂即被称之为FactoryBean

标签:初始化,ParentRunner,java,Spring,springframework,Beans,beans,org,junit
来源: https://www.cnblogs.com/vielat/p/15631571.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有