SpringIoC

IOC容器

IOC控制反转,是一种设计原则,用于降低程序的耦合性,其中最常见的方式是依赖注入(DI),将不同对象之间的关联关系由原来的由开发人员管理转化为由spring进行管理,在设置对象关联关系的方法上,主要有注解和XML两种方式

注解的方式

主要有以下几个:

  1. 组件扫描
  • @Component:把普通的对象实例话到Spring容器中,当需要调用实例话对象时,可以直接从Spring容器中获取
  • @ComponentScan:扫描项目从中找出需要装配的类自动装配到spring的bean容器中
  1. 自动装配
  • @Autowired:在获取bean对象时自动执行此内容,自动满足bean之间的依赖
  1. 定义配置类
  • @Configuration:表示当前类是一个配置类
package hello;

/* MessageService.java */
import org.springframework.stereotype.Component;

/**
 * 打印输出
 */
@Component
public class MessageService {

    public MessageService() {
        System.out.println("MessageService...");
    }

    public String getMessage(){
        return "Hello world.";
    }
}

/* MessagePrinter.java */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MessagePrinter {

    public MessagePrinter() {
        System.out.println("MessagePrinter...");
    }

    /**
     * 建立与MessageService的关联关系
     */
    private MessageService service;

    public MessageService getService() {
        return service;
    }

    @Autowired
    public void setService(MessageService service) {
        this.service = service;
    }

    public void printMessage(){
        System.out.println(this.service.getMessage());
    }
}

/* ApplicatinSpring.java */
package hello;

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

@ComponentScan
public class ApplicationSpring {

    public static void main(String[] args) {
        System.out.println("applicationSpring");
        //初始化Spring容器
        ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationSpring.class);
        //从容器中获取MessagePrinter对象
        MessagePrinter printer = context.getBean(MessagePrinter.class);
        //从容器中获取MessageService对象
        //MessageService service = context.getBean(MessageService.class);

        //因为已经有@Autowired注解,不用执行set方法
        //printer.setService(service);
        printer.printMessage();
    }
}

XML配置文件方式

通过在resources目录下创建xml文件进行配置,property name元素是指JavaBean属性的名称,以及ref元素指的是另一个bean定义的名称。元素id和ref元素之间的这种联系表达了协作对象之间的依赖关系。

<?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">
<!--
    bean元素:描述当前的对象需要由spring容器管理
    id属性:标识对象,未来在应用程序中可以根据id获取对象
    class属性:被管理对象的类全名
-->
    <bean id="service" class="hello.MessageService"></bean>

    <bean id="printer" class="hello.MessagePrinter">
        <property name="service" ref="service"></property>
    </bean>
</beans>
package hello;

        import org.springframework.context.ApplicationContext;
        import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationSpring {

    public static void main(String[] args) {
        System.out.println("applicationSpring");

        //初始化Spring容器
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从容器中获取MessagePrinter对象
        MessagePrinter printer = context.getBean(MessagePrinter.class);
        //打印消息
        printer.printMessage();
    }
}

Spring使用junit4单元测试

  • 在maven中添加依赖:junit,spring-test
  • 在测试类上添加注解@RunWith(SpringJUnit4ClassRunner.class)以及加载配置类@ContextConfiguration(classes=AppConfig.class)
package soundsystem;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class AppTest {
    @Autowired
    private CDPlayer player;
    @Test
    public void testPlay(){
        player.play();
    }
}

bean装配

Spring中装配bean主要有三种方式:

  • 隐式的bean发现机制和自动装配
  • 在java中进行显示的配置
  • 在XML中进行显示的配置

隐式自动配置

通过使用注解的方式

  1. 组件扫描
  • @Component:把普通的对象实例化到Spring容器中,当需要调用实例话对象时,可以直接从Spring容器中获取

    @Controller,@Service,@Repository的作用与@Component相同,只是更加明确其具体作用,分别对应控制层,服务层和dao层

  • @ComponentScan:扫描项目从中找出需要装配的类自动装配到spring的bean容器中,默认的扫描路径为当前类所在的包及其子包,可以为其设置参数扫描指定内容

    扫描指定的包:@ComponentScan(“com.xm.demo”)
    扫描多个包:@ComponentScan(basePackages = {“com.xm.demo.web”,”com.xm.demo.service”,com.xm.demo.dao”})
    扫描指定类:@ComponentScan(basePackageClasses = {UserController.class,UserService.class,UserDao.class})

  1. 自动装配
  • @Autowired:自动装配,在获取bean对象时自动执行此内容,自动满足bean之间的依赖
  • @Value:对普通变量可以直接使用value注解注入,通过参数value赋值

    @Value(value=”value”) 或者 @Value(“value”)

  1. 定义配置类
  • @Configuration:表示当前类是一个配置类,此时获取bean对象时,AnnotationConfigApplicationContext的参数为配置类

@Autowired的四种使用情况

  • 用在构造函数上(多个依赖的情况):效率最高的方式
  • 用在成员变量上:最便捷的方式
  • 用在setter方法上
  • 用在任意方法上

required属性

默认情况下,如果被@Autowired注解的类没有事先放入容器中,自动装配就会失败。默认行为是将带注释的方法,构造函数和字段视为指示所需的依赖项。此时可以使用autowire的required属性,将其赋值为false。

@Autowired(required=false) 表示该属性不是自动装配所必需的。如果无法自动装配,则会忽略该属性。

使用接口

对于程序中的接口,一般@component注解都是修饰其实现类,而在程序中自动装载@Autowired使用的是接口类

/**
 * 接口
**/
public interface UserService {
    void add();
}
/**
 * 接口实现类
**/
@Component//修饰的是接口实现类
public class UserServiceNormal implements UserService {
    @Override
    public void add() {
        System.out.println("添加用户");
    }
} 
/**
 * 测试
**/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class UserServiceTest {
    @Autowired//修饰的是接口
    private UserService userService;

    @Test
    public void testAdd(){
        userService.add();
    }
}

自动装配的歧义性

当一个接口有多个实现类,并且每个实现类都标注了@Component,那么当对接口类使用@Autowired时,运行会因为无法确定具体是要加载哪个类而报错

解决方法:

  1. 首选bean
    对优先的实现类添加注释@Primary,这样在自动装配的时候就会优先使用该实现类,但其局限性是只能对一个实现类使用,当存在多个实现类都修饰@Primary时仍然会报错;另外有时候在程序设计的时候并不能马上就决定哪个优先,而是要根据具体情况而定。
  2. 使用限定符
    对多个实现类使用@Qualifier("name")进行修饰,同时指定每个实现类的名称name,在声明变量时,同样在变量前加上@Qualifier(“name”),同时写明希望调用的实现类的name
  3. 使用限定符和类id
    可以在声明@Component的时候顺便为该bean指定一个id,即@Component("id"),在装配的时候使用@Qualifier("id")进行指定,默认如果不指定id的话,id是首字母小写的类名
  4. 使用java标准的Resource
    在装配的位置使用@Resource(name="id"),代替@Autowired和@Qualifier(“name”),其作用相当于两个的结果,使用前需要添加依赖包javax.annotation

配置组件扫描的多种方式

  1. 通过定义Config类专门用于组件扫描
/** Config.class **/
@Configuration//标识这是一个配置文件
@ComponentScan(basePackages = {"com.xm.demo.web","com.xm.demo.service","com.xm.demo.dao"})
public class AppConfig {

}

/** 测试类 **/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)//加载组件
public class UserServiceTest {
    @Autowired
    private UserController userController;

    @Test
    public void testAdd(){
        userController.add();
    }
}
  1. 通过xml的方式进行配置
    在resources目录下通过创建spring配置文件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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.xm.demo.service"/>
    <context:component-scan base-package="com.xm.demo.dao"/>
    <context:component-scan base-package="com.xm.demo.web"/>
</beans>
@ContextConfiguration("classpath:applicationContext.xml")//指向xml配置文件
public class UserServiceTest {
    @Autowired
    private UserController userController;

    @Test
    public void testAdd(){
        userController.add();
    }
}

java显示装配

配置Bean对象

@Configuration
public class AppConfig {

    @Bean//标识该类在spring中能够被自动装配
    public UserDao userDaoNormal(){
        System.out.println("自动调用创建UserDao对象");
        return new UserDaoNormal();
    }
}

以后调用的时候就只需要跟注解一样,添加@ContextConfiguration(classes=AppConfig.class)并在需要自动装载的地方是有@Autowired就可以

通过构造函数依赖注入

当调用的方式需要依赖于其他类的方法时,可以使用

package com.xm.demo.config;

import com.xm.demo.dao.UserDao;
import com.xm.demo.dao.impl.UserDaoNormal;
import com.xm.demo.service.UserService;
import com.xm.demo.service.impl.UserServiceNormal;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean//标识该类在spring中能够被自动装配
    public UserDao userDaoNormal(){
        System.out.println("自动调用创建UserDao对象");
        return new UserDaoNormal();
    }

    @Bean
    public UserService userServiceNormal(){
        System.out.println("自动依赖注入创建UserServiceNormal");
        UserDao userDao = userDaoNormal();
        return new UserServiceNormal(userDao);
    }
}

当Spring程序加载时,会自动执行@bean的语句,但是上面的userDaoNormal()不会执行两次,因为执行前spring会先判断是否已经创建了该对象,如果已经创建了,直接返回该对象(单例模式

在@bean修饰的方法中使用参数

在上面@bean方法修饰的UserServiceNormal方法中传入参数,Spring会寻找是否已经已经创建了类对象,如果有就直接返回该例

@Bean
public UserService userServiceNormal(UserDao userDao){
    return new UserServiceNormal(userDao);
}

通过setter方法

@Bean
public UserService userServiceNormal(UserDao userDao){
    System.out.println("自动依赖注入创建UserServiceNormal");
    UserServiceNormal userService = new UserServiceNormal();
    userService.setUserDao(userDao);
    return userService;
}

XML中显示装配

创建spring的xml配置文件,在程序中使用ClassPathXmlApplicationContext加载xml文件获得上下文,之后可以通过上下文获取bean对象,默认创建的bean对象是单例的,同时xml默认会为bean创建一个name属性,其值默认为包名.类名#0/1/2/....

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

    <bean class="com.xm.demo.soundsystem.CompactDisc"/>
</beans>
public class ApplicationSpring {
    public static void main(String[] args) {
        System.out.println("ApplicationSpring is running.....");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CompactDisc cd = context.getBean(CompactDisc.class);
        cd.play();
    }
}

多个bean的情况

当有多个相同bean的时候,可以通过在xml中设置id,在获取bean的时候通过getBean传入name参数指定使用的id

<?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">
    <bean id="compactDisc1" class="com.xm.demo.soundsystem.CompactDisc"/>
    <bean id="compactDisc2" class="com.xm.demo.soundsystem.CompactDisc"/>
</beans>
import com.xm.demo.soundsystem.CompactDisc;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationSpring {
    public static void main(String[] args) {
        System.out.println("ApplicationSpring is running.....");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CompactDisc cd = (CompactDisc) context.getBean("compactDisc2");//指定id
        cd.play();
    }
}

使用注解配置

package com.xm.demo.soundsystem;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AppTest {
    @Autowired
    private CompactDisc compactDisc1;//对应xml文件的compactDisc1

    @Autowired
    private CompactDisc compactDisc2;//对应xml文件的compactDisc2

    @Autowired
    @Qualifier("compactDisc2")
    private CompactDisc compactDisc3;

    @Test
    public void test01(){
        compactDisc1.play();
        compactDisc2.play();
        //构造方法不会有第三遍执行,compactDisc3使用的是2的实例,所以它们的地址相同
        compactDisc3.play();
    }
}

id和name属性

在xml的bean配置中,id和name属性的作用是一样的,相当于变量名,但是name可以为一个bean取多个别名,不同别名之间使用 ;,空格隔开,另外,name可以有特殊字符

<bean name="compactDisc1 compactDisc1-2 compactDisc1-3" class="com.xm.demo.soundsystem.CompactDisc"/>

构造方法的依赖注入

两种方式:

  1. 通过添加constructor-arg属性指定构造函数的依赖项
<bean id="cdPlayer" class="com.xm.demo.soundsystem.CDPlayer">
    <!--构造函数注入,铜鼓ref指定具体注入的对象-->
    <constructor-arg ref="compactDisc1"/>
</bean>
  1. 使用c名称空间注入

需要在xml文件的顶部先引入c名称空间

xmlns:c=”http://www.springframework.org/schema/c"

之后可以使用如下配置:

<bean id="cdPlayer2" class="com.xm.demo.soundsystem.CDPlayer" c:cd-ref="compactDisc2"></bean>

参数说明:参数格式可以有两种

  • c:构造函数参数名-ref=”注入类id”
  • c:_0-ref=”注入类id“

    _0表示第一个参数,第二个参数为_1,以此类推

简单类型注入

对于类中的简单类型属性,可以通过在xml的构造函数注入中使用value进行值的注入,有一下几种注入方法,如果没有提供参数,默认按照构造函数的参数排列进行赋值

 <bean name="compactDisc1 compactDisc1-2 compactDisc1-3" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg value="I Do"/>
    <constructor-arg value="xiaoming1"/>
</bean>

<bean id="compactDisc2" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg index="0" value="I Do"/>
    <constructor-arg index="1" value="xiaoming2"/>
</bean>

<bean id="compactDisc3" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg name="title" value="I Do"/>
    <constructor-arg name="artist" value="xixoming3"/>
</bean>

<bean id="compactDisc4" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg type="java.lang.String" value="I Do"/>
    <constructor-arg type="java.lang.String" value="xiaoming4"/>
</bean>

<bean id="compactDisc5" class="com.xm.demo.soundsystem.CompactDisc"
    c:title="I Do"
    c:artist="xiaoming5"/>

List类型注入

  1. 若List中的元素是简单类型,可以使用如下配置
<bean id="compactDisc3" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg name="title" value="I Do"/>
    <constructor-arg name="artist" value="xixoming3"/>
    <constructor-arg name="tracks" >
        <list>
            <value>Dream Possible</value>
            <value>Opera2</value>
            <value>Counting Start</value>
        </list>
    </constructor-arg>
</bean>
  1. 若List中的元素是bean类型,则使用如下配置
<bean id="compactDisc6" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg name="title" value="I Do"/>
    <constructor-arg name="artist" value="xixoming3"/>
    <constructor-arg name="tracks" >
        <list>
            <ref bean="music1"/>
            <ref bean="music2"/>
            <ref bean="music3"/>
        </list>
    </constructor-arg>
</bean>

set类型注入

Spring中的set使用的是LinkedHashSet,能够保证按照顺序存储,在配置上只需要将xml中的list节点改为set即可

map类型注入

<bean id="compactDisc6" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg name="title" value="I Do"/>
    <constructor-arg name="artist" value="xixoming3"/>
    <constructor-arg name="tracks" >
        <map>
        <!-- 如果值是普通类型,使用这种形式 -->
        <entry key="music1" value="xxx"/>
        <!-- 如果值是类对象 -->
            <entry key="music1" value-ref="music1"/>
            <entry key="music2" value-ref="music2"/>
            <entry key="music3" value-ref="music3"/>
        </map>
    </constructor-arg>
</bean>

数组类型注入

<bean id="compactDisc6" class="com.xm.demo.soundsystem.CompactDisc">
    <constructor-arg name="title" value="I Do"/>
    <constructor-arg name="artist" value="xixoming3"/>
    <constructor-arg name="tracks" >
        <array>
            <!-- 如果数组类型是普通类型 -->
            <value>music1</value>
            <!-- 如果数组类型是类对象 -->
            <ref bean="music1"/>
            <ref bean="music2"/>
            <ref bean="music3"/>
        </array>
    </constructor-arg>
</bean>

Peoperty类型注入

<property name="properties">
    <props>
        <prop key="username">root</prop>
        <prop key="password">root</prop>
    </props>
</property>

属性注入

通过xml对类的setter方法进行属性注入。
属性指的是set名方法其后面的内容,而成员变量指的是类中定义的内部变量,例如:对成员变量的set方法setAge1,此时age是成员变量,age1是属性,xml中配置的name与属性相对应

<?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">
    
    <!-- 配置属性注入 -->
    <bean id="music1" class="com.xm.demo.soundsystem.Music">
        <property name="title" value="两只老虎"/>
        <property name="duration" value="100秒"/>
    </bean>

    <bean id="music2" class="com.xm.demo.soundsystem.Music">
        <property name="title" value="澎湖湾"/>
        <property name="duration" value="200秒"/>
    </bean>
</beans>

属性中若包含数组或列表,则与上面所说的注入方式相同

<bean id="compactDisc1" class="com.xm.demo.soundsystem.CompactDisc">
    <property name="title" value="music1"/>
    <property name="artist" value="xiaoming"/>
    <property name="tracks">
        <array>
            <ref bean="music1"/>
            <ref bean="music2"/>
        </array>
    </property>
</bean>

若包含对象:

<bean id="CDPlayer1" class="com.xm.demo.soundsystem.CDPlayer">
    <property name="cd" ref="compactDisc1"/>
</bean>

p名称空间

用于代替属性的注入,但是不能代替数组,列表等类型,只能代替普通类型和对象类型,主要用于jdbc配置数据源

首先需要在xml文件的头部加入命名空间

xmlns:p=”http://www.springframework.org/schema/p"

格式上,若是普通类型

<bean id="music2" class="com.xm.demo.soundsystem.Music"
        p:title="澎湖湾"
        p:duration="200秒"/>

若是对象

<bean id="CDPlayer1" class="com.xm.demo.soundsystem.CDPlayer"
        p:cd-ref="compactDisc1"/>

spel注入

springEL表达式注入

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>
<bean id="taxCalculator" class="org.spring.samples.TaxCalculator">
    <property name="defaultLocale" value="#{ systemProperties['user.region'] }"/>

    <!-- other properties -->
</bean>

util名称空间

可以用于数组,集合的注入
首先导入命名空间(idea自动导入)

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

使用方法:list即包括数组,也包括列表,除此之外,util还有set,map等方法

<util:list id="trackList">
    <ref bean="music1"/>
    <ref bean="music2"/>
</util:list>
<bean id="compactDisc1" class="com.xm.demo.soundsystem.CompactDisc"
        p:title="music1"
        p:artist="xiaoming"
        p:tracks-ref="trackList">
</bean>

bean的作用域

默认情况下,bean都是单例的

  • 无论是否去主动获取或注入bean对象,String上下文一加载就会创建bean对象
  • 无论注入多少次,拿到的都是同一个对象

可以修改bean的作用域,在xml中,bean有一个名为scope的属性,其值可以为一下四个:

  • 单例(Sinleton):在整个应用程序中,只创建bean的一个实例
  • 原型(ProtoType):每次注入或通过spring上下文获取的时候,都会创建一个新的bean实例,当第一次加载的时候不会创建bean对象
  • 会话(Session):在web应用中,为每个会话创建一个bean实例
  • 请求(Request):在web应用中,为每个请求创建一个bean实例

更改作用域的几种方式:

  1. xml文件在bean元素中添加scope属性
<bean id="notepad" class="com.xm.demo.NotePad" scope="prototype"></bean>
  1. 使用@scope注解

@Scope(“prototype”)

@Scope(scopeName = “prototype”)

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

  1. 使用javaconfig配置
@Configuration
public class AppConfig {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Notepad3 notepad3(){
        return new Notepad3();
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class Notepad3Test {

    @Autowired
    private Notepad3 notePad1;
    @Autowired
    private Notepad3 notePad2;

    @Test
    public void test01(){
        System.out.println(notePad1==notePad2);
    }
}

延迟加载

当bean的作用域是单例时,默认是上下文初始化的时候就初始化了,可以配置其延迟加载,当需要用到的时候再自动加载该bean对象;
当bean的作用域是prototype时,在获取对象时才创建bean对象

<bean id="notepad" class="com.xm.demo.NotePad" scope="prototype" lazy-init="true"></bean>

或者使用 @Lazy修饰

对象的销毁和初始化

<bean id="notepad" class="com.xm.demo.NotePad"
    destroy-method="destroy"
    init-method="init"/>
public void test01(){
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    NotePad notepad1 = (NotePad)context.getBean("notepad");
    context.destroy();//主动调用销毁方法
    context.close();//关闭容器,会自动触发销毁方法
}

也可以使用注解修饰初始化和注销方法,需要先引入依赖

 <dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>jsr250-api</artifactId>
    <version>1.0</version>
</dependency>
@PostConstruct
public void init(){
    System.out.println("Notepad的初始化方法");
}

@PreDestroy
public void destroy(){
    System.out.println("Notepad的销毁方法");
}

Spring中工厂方法创建bean对象

<!--静态工厂的方法 static方法-->
<bean id="person1" class="com.xm.demo.PersonFactory" factory-method="createPerson1"/>

<!--实例工厂的方法 非static方法-->
<bean id="personFactory" class="com.xm.demo.PersonFactory"/>
<bean id="person2" factory-bean="personFactory" factory-method="createPerson2"/>