SpringIoC
IOC容器
IOC控制反转,是一种设计原则,用于降低程序的耦合性,其中最常见的方式是依赖注入(DI),将不同对象之间的关联关系由原来的由开发人员管理转化为由spring进行管理,在设置对象关联关系的方法上,主要有注解和XML两种方式
注解的方式
主要有以下几个:
- 组件扫描
- @Component:把普通的对象实例话到Spring容器中,当需要调用实例话对象时,可以直接从Spring容器中获取
- @ComponentScan:扫描项目从中找出需要装配的类自动装配到spring的bean容器中
- 自动装配
- @Autowired:在获取bean对象时自动执行此内容,自动满足bean之间的依赖
- 定义配置类
- @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中进行显示的配置
隐式自动配置
通过使用注解的方式
- 组件扫描
@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})
- 自动装配
- @Autowired:自动装配,在获取bean对象时自动执行此内容,自动满足bean之间的依赖
- @Value:对普通变量可以直接使用value注解注入,通过参数value赋值
@Value(value=”value”) 或者 @Value(“value”)
- 定义配置类
- @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时,运行会因为无法确定具体是要加载哪个类而报错
解决方法:
- 首选bean
对优先的实现类添加注释@Primary
,这样在自动装配的时候就会优先使用该实现类,但其局限性是只能对一个实现类使用,当存在多个实现类都修饰@Primary时仍然会报错;另外有时候在程序设计的时候并不能马上就决定哪个优先,而是要根据具体情况而定。 - 使用限定符
对多个实现类使用@Qualifier("name")
进行修饰,同时指定每个实现类的名称name,在声明变量时,同样在变量前加上@Qualifier(“name”),同时写明希望调用的实现类的name - 使用限定符和类id
可以在声明@Component的时候顺便为该bean指定一个id,即@Component("id")
,在装配的时候使用@Qualifier("id")
进行指定,默认如果不指定id的话,id是首字母小写的类名 - 使用java标准的Resource
在装配的位置使用@Resource(name="id")
,代替@Autowired和@Qualifier(“name”),其作用相当于两个的结果,使用前需要添加依赖包javax.annotation
配置组件扫描的多种方式
- 通过定义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();
}
}
- 通过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"/>
构造方法的依赖注入
两种方式:
- 通过添加
constructor-arg
属性指定构造函数的依赖项
<bean id="cdPlayer" class="com.xm.demo.soundsystem.CDPlayer">
<!--构造函数注入,铜鼓ref指定具体注入的对象-->
<constructor-arg ref="compactDisc1"/>
</bean>
- 使用c名称空间注入
需要在xml文件的顶部先引入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类型注入
- 若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>
- 若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文件的头部加入命名空间
格式上,若是普通类型
<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实例
更改作用域的几种方式:
- xml文件在bean元素中添加
scope
属性
<bean id="notepad" class="com.xm.demo.NotePad" scope="prototype"></bean>
- 使用
@scope
注解
@Scope(“prototype”)
@Scope(scopeName = “prototype”)
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- 使用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"/>