首页 > 代码库 > Spring框架第一篇之Bean的装配

Spring框架第一篇之Bean的装配

一、默认装配方式

代码通过getBean();方式从容器中获取指定的Bean实例,容器首先会调用Bean类的无参构造器,创建空值的实例对象。

举例:

首先我在applicationContext.xml配置文件中配置了一个bean:

<?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">

    <!-- 注册Service 这里相当于容器做了SomeServiceImpl myService = new SomeServiceImpl(); -->
    <bean id="myService" class="com.ietree.spring.basic.ioc.SomeServiceImpl"/>
    
</beans>

创建SomeServiceImpl对象,但需要注意的是该类的只具有带参构造函器,没有无参构造器:

package com.ietree.spring.basic.ioc;

/**
 * 实现类
 * 
 * @author Root
 */
public class SomeServiceImpl implements ISomeService {

    private int a;
    
    // 这里注释掉了无参构造函数,希望容器通过带参构造函数创建对象
//    public SomeServiceImpl() {
//        System.out.println("执行无参构造器,创建SomeServiceImpl对象");
//    }

    public SomeServiceImpl(int a) {
        this.a = a;
    }

    @Override
    public void doSomeThing() {
        System.out.println("执行doSomeThing()方法...");
    }

}

测试:

@Test
public void testConstructor() {

    // 创建容器对象,加载Spring配置文件
    // ClassPathXmlApplicationContext会从类路径下查找配置文件
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    ISomeService service = (ISomeService) ac.getBean("myService");
    service.doSomeThing();
}

此时程序会报以下的错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘myService‘ defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ietree.spring.basic.ioc.SomeServiceImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.ietree.spring.basic.ioc.SomeServiceImpl.<init>()
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1155)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1099)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.ietree.spring.basic.test.MyTest.testConstrutor(MyTest.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ietree.spring.basic.ioc.SomeServiceImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.ietree.spring.basic.ioc.SomeServiceImpl.<init>()
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1147)
    ... 36 more
Caused by: java.lang.NoSuchMethodException: com.ietree.spring.basic.ioc.SomeServiceImpl.<init>()
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:80)
    ... 37 more

解析:这里的错误报的很明显,没有发现默认的构造器。

修改:为该类加上无参构造器:

package com.ietree.spring.basic.ioc;

/**
 * 实现类
 * 
 * @author Root
 */
public class SomeServiceImpl implements ISomeService {

    private int a;
    
    public SomeServiceImpl() {
        System.out.println("执行无参构造器,创建SomeServiceImpl对象");
    }

    public SomeServiceImpl(int a) {
        this.a = a;
    }

    @Override
    public void doSomeThing() {
        System.out.println("执行doSomeThing()方法...");
    }

}

此时,再次运行测试用例,会发现运行成功。

结论:Spring容器实际上是使用了类的反射机制,会首先调用Bean类的无参构造器创建实例对象。

二、动态工厂Bean

 

三、静态工厂Bean

 

四、容器中的Bean的作用域

 

五、Bean后处理器

 

六、定制Bean的生命周期

 

七、<bean/>标签的id属性与name属性

 

Spring框架第一篇之Bean的装配