Spring Xml 方式 Bean 管理
文章目录
一、Spring 工厂类
传统的由 BeanFactory 创建工厂的方法已过时,现在直接从文件路径或类路径得到 ApplicationContext Spring工厂。
- 上面是从类路径中读取配置文件: ClassPathXmlApplicationContext
- 从磁盘目录中读取配置文件 : FileSystemXmlApplicationContext
public void demo3() {
// 创建Spring工厂
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
// 通过工厂获得类
UserService userService = (UserService) applicationContext.getBean("userService");
userService.sayHello();
}
- Spring老版本的工厂类(了解,已过时)
public void demo4() {
// 创建工厂类
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
// 通过工厂获得类
UserService userService = (UserService) beanFactory.getBean("userService");
userService.sayHello();
}
二、XML方法实例化Bean的三种方式
1、使用类构造器实例化(默认无参数)
//1***** Bean1
public class Bean1 {
public Bean1() {
System.out.println("Bean1实例化成功。");
}
}
//2***** applicationContext.xml 中添加配置
<!-- Bean实例化方式1:无参构造器方法 -->
<bean id="bean1" class="com.moc.ioc.demo2.Bean1" />
//3***** 测试
public class BeanTestDemo {
@Test
public void demo1() {
// 创建工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例
Bean1 bean1 = (Bean1)applicationContext.getBean("bean1");
}
}
2、使用静态工厂方法实例化(简单工厂模式)
//1***** Bean2
public class Bean2 {
}
//2***** Bean2Factory
public class Bean2Factory {
public static Bean2 createBean2() {
System.out.println("Bean2工厂创建Bean2");
return new Bean2();
}
}
//3***** applicationContext.xml 中添加配置
<!-- Bean实例化方式2:静态工厂方法 -->
<bean id="bean2" class="com.moc.ioc.demo2.Bean2Factory" factory-method="createBean2" />
//4***** 测试
@Test
public void demo2() {
// 创建工厂 (加载配置文件时,会把配置文件中所有的类都实例化)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例
Bean2 bean2 = (Bean2)applicationContext.getBean("bean2");
}
3、使用实例工厂方法实例化(工厂方法模式)
//1***** Bean3
public class Bean3 {
}
//2***** Bean3Factory
public class Bean3Factory {
public Bean3 createBean3() {
System.out.println("Bean3工厂创建Bean3");
return new Bean3();
}
}
//3***** applicationContext.xml 中添加配置
<!-- Bean实例化方式2:实例工厂方法 -->
<bean id="bean3Factory" class="com.moc.ioc.demo2.Bean3Factory" />
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3" />
//4***** 测试
@Test
public void demo3() {
// 创建工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例
Bean3 bean3 = (Bean3)applicationContext.getBean("bean3");
}
4、Bean标签的常见属性
id和name
- 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称
- id 属性在IOC容器中必须是唯一的
- 如果Bean的名称中含有特殊字符,就需要使用name属性
class
class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例
scope
类别 | 描述 |
---|---|
singleton | 在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在(默认) |
prototype | 每次调用getBean()时都会返回一个新的实例(整合Struct2时用到) |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同的HTTPSession使用不同的Bean。该作用域仅适用于WebApplicationContext环境 |
三、Bean的生命周期
1、Bean标签中配置的两个生命周期方法
init-method:当bean被载入到容器的时候调用init
destory-method:当bean从容器中删除的时候调用destroy(scope=singleton有效)
<bean id="xxx" class="..." init-method="init" destory-method="destroy" />
- 测试
//1***** Bean
public class LifeDemo {
public LifeDemo() {
System.out.println("Demo被实例化啦...");
}
public void setup() {
System.out.println("Demo被初始化啦...");
}
public void teardown() {
System.out.println("Demo被销毁啦...");
}
}
//2***** applicationContext.xml 中添加配置
<bean id="LifeDemo" class="com.moc.ioc.demo3.LifeDemo" init-method="setup" destroy-method="teardown" />
//3***** 测试
public class LifeTestDemo {
@Test
public void demo1() {
// 创建工厂 (这里要关闭工厂,需要使用实现类而不是接口)
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过工厂获得类的实例
LifeDemo lifeDemo = (LifeDemo)applicationContext.getBean("LifeDemo");
// 关闭工厂,会执行Bean的销毁
applicationContext.close();
}
}
2、Bean的完整生命周期
- instantiate bean对象实例化
- populate properties 封装属性
- 如果Bean实现BeanNameAware 执行 setBeanName
- 如果Bean实现BeanFactoryAware 或者ApplicationContextAware 设置工厂setBeanFactory 或者上下文对象 setApplicationContext
- 如果存在类实现BeanPostProcessor(后处理Bean) 执行postProcessBeforelnitialization
- 如果Bean实现InitializingBean 执行 afterPropertiesSet
- 调用 <bean init-method= “init” >指定初始化方法 init
- 如果存在类实现BeanPostProcessor(处理Bean) 执行postProcessAfterInitialization
- 执行业务方法
- 如果Bean实现DisposableBean 执行 destroy
- 调用<bean destroy-method= “customerDestroy” >指定销毁方法customerDestroy
- 测试
//1***** Bean
public class FullLife implements BeanNameAware, ApplicationContextAware,
InitializingBean, DisposableBean {
private String name;
public FullLife() {
System.out.println("第一步:初始化 ...");
}
public void setName(String name) {
System.out.println("第二步:读取配置文件,设置属性");
this.name = name;
}
@Override
public void setBeanName(String s) {
System.out.println("第三步:设置Bean的名称" + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("第四步:了解工程信息 ...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("第六步:属性设置后执行 ...");
}
public void setup() {
System.out.println("第七步:执行<bean>中指定的init-method方法");
}
public void run() {
System.out.println("第九步:执行Bean自身的业务方法(除了其余步骤以外的其他方法,方法名任意)");
}
@Override
public void destroy() throws Exception {
System.out.println("第十步:执行Spring的销毁方法 ...");
}
public void teardown() {
System.out.println("第十一步:执行<bean>中指定的destroy-method方法");
}
}
//2***** 存在类实现BeanPostProcessor
// 该类在每个Bean的生命周期中都会只执行
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException {
System.out.println("第五步:初始化前方法 ...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String s) throws BeansException {
System.out.println("第八步:初始化后方法 ...");
return bean;
}
}
//3***** applicationContext.xml 中添加配置
<!-- Bean的全生命周期 -->
<bean id="fullLife" class="com.moc.ioc.demo3.FullLife" init-method="setup" destroy-method="teardown">
<property name="name" value="小红"/>
</bean>
<bean class="com.moc.ioc.demo3.MyBeanPostProcessor"/>
//4***** 测试
public class LifeTestDemo {
@Test
public void demo2() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
FullLife fullLife = (FullLife)applicationContext.getBean("fullLife");
fullLife.run();
applicationContext.close();
}
}
3、增强一个Bean类的方法(aop)
使用 实现BeanPostProcessor类 来增强 Bean类中的方法。
//1***** 一个Bean类的接口
public interface UserDao {
public void findAll();
public void save();
}
//2***** 一个Bean实现类
public class UserDaoImpl implements UserDao {
@Override
public void findAll() { System.out.println("查询用户..."); }
@Override
public void save() { System.out.println("保存用户..."); }
}
//3***** applicationContext.xml 中添加配置
<bean id="userDao" class="com.moc.ioc.demo3.UserDaoImpl"/>
<bean class="com.moc.ioc.demo3.MyBeanPostProcessor"/>
//4***** 实现BeanPostProcessor的类来增强Bean类中的指定方法
public class MyBeanPostProcessor implements BeanPostProcessor {
//第八步:初始化后方法
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
if ("userDao".equals(beanName)) {
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("save".equals(method.getName())) {
System.out.println("保存之前进行权限校验");
return method.invoke(bean, args);
}
return method.invoke(bean, args);
}
});
return proxy;
} else {
return bean;
}
}
}
//5***** 测试
public class TestDemo {
@Test
public void demo() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao)applicationContext.getBean("userDao");
userDao.findAll();
userDao.save();
}
}
四、XML方式的属性注入
- 对于类成员变量,注入方式有三种
-
构造函数注入
-
属性setter方法注入
-
接口注入
Spring支持前两种。
1、构造方法注入
通过构造方法注入Bean 的属性值或依赖的对象,它保证了Bean 实例在实例化后就可以使用。
构造器注入在 <constructor-arg> 元素里声明的属性。
//*****1 Bean实体类
public class User {
private String name;
private Integer age;
public User(String name,Integer age){
this.name = name;
this.age = age;
}
@Override
public String toString() {...}
}
//*****2 applicationContext.xml 配置Bean
<bean id="user" class="com.imooc.ioc.demo4.User">
<constructor-arg name="name" value="张三" />
<constructor-arg name="age" value="23"/>
</bean>
//*****3 测试
public class SpringDemo {
@Test
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)applicationContext.getBean("user");
System.out.println(user);
}
}
2、set方法注入
使用set方法注入,在Spring配置文件中,通过 <property> 设置注入的属性。
//*****1 Bean实体类
public class Person {
private String name;
private Integer age;
private Cat cat;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public Cat getCat() { return cat; }
public void setCat(Cat cat) { this.cat = cat; }
@Override
public String toString() { ... }
}
//*****2 Bean实体类注入的引用类
public class Cat {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String toString() { ... }
}
//*****3 applicationContext.xml 配置Bean
<bean id="person" class="com.imooc.ioc.demo4.Person">
<property name="name" value="李四"/>
<property name="age" value="32"/>
<property name="cat" ref="cat"/>
</bean>
<bean id="cat" class="com.imooc.ioc.demo4.Cat">
<property name="name" value="ketty"/>
</bean>
//*****4 SpringDemo类添加测试方法
@Test
public void demo2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);
}
3、p名称空间
为了简化XML文件配置,Spring从2.5开始引入一个新的p名称空间。
p:<属性名>="xxx”引入常量值
p:<属性名>-ref="xxx”引用其它Bean对象
<!-- 采用p名称空间完成上面Person的Bean配置 -->
<beans>里添加属性: xmlns:p="http://www.springframework.org/schema/p"
<bean id="person" class="com.imooc.ioc.demo4.Person" p:name="大黄" p:age="34" p:cat-ref="cat"/>
<bean id="cat" class="com.imooc.ioc.demo4.Cat" p:name="小黄"/>
4、SpEL注入
SpEL(spring expression language,spring表达式语言):对依赖注入进行简化
- 语法:#{表达式}
- <bean id=" " value="#{表达式}">
#{‘hello’}:使用字符串(单引号)
#{Beanld}:使用另一个bean
#{Beanld.method()}:使用另一个bean的方法
#{T(java.lang.Math).PI}:使用静态字段或方法
//*****1 Bean实体类
public class Product {
private String name;
private Double price;
private Category category;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
public Category getCategory() { return category; }
public void setCategory(Category category) { this.category = category; }
@Override
public String toString() { ... }
}
//*****2 演示使用SpEL提供的类
public class ProductInfo {
public Double calculatePrice(){ return Math.random() * 200; }
}
public class Category {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String toString() { ... }
}
//*****3 applicationContext.xml 配置Bean
<bean id="category" class="com.imooc.ioc.demo4.Category">
<property name="name" value="#{'服装'}"/>
</bean>
<bean id="productInfo" class="com.imooc.ioc.demo4.ProductInfo"/>
<bean id="product" class="com.imooc.ioc.demo4.Product">
<property name="name" value="#{'男装'}"/>
<property name="price" value="#{productInfo.calculatePrice()}"/>
<property name="category" value="#{category}"/>
</bean>
//*****4 SpringDemo类添加测试方法
@Test
public void demo3(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Product product = (Product)applicationContext.getBean("product");
System.out.println(product);
}
4、复杂类型的属性注入
- 数组类型的属性注入
- List集合类型的属性注入
- Set集合类型的属性注入
- Map集合类型的属性注入
- Properties类型的属性注入
//*****1 Bean实体类
public class CollectionBean {
private String[] arrs; // 数组类型
private List<String> list;// List集合类型
private Set<String> set; // Set集合类型
private Map<String,Integer> map;// Map集合类型
private Properties properties; // 属性类型
public String[] getArrs() { return arrs; }
public void setArrs(String[] arrs) { this.arrs = arrs; }
public List<String> getList() { return list; }
public void setList(List<String> list) { this.list = list; }
public Set<String> getSet() { return set; }
public void setSet(Set<String> set) { this.set = set; }
public Map<String, Integer> getMap() { return map; }
public void setMap(Map<String, Integer> map) { this.map = map; }
public Properties getProperties() { return properties; }
public void setProperties(Properties properties) {this.properties=properties;}
@Override
public String toString() { ... }
}
//*****2 applicationContext.xml 配置Bean
<bean id="collectionBean" class="com.imooc.ioc.demo5.CollectionBean">
<!--数组类型-->
<property name="arrs">
<list>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</list>
</property>
<!--List集合的属性注入-->
<property name="list">
<list>
<value>111</value>
<value>222</value>
<value>333</value>
</list>
</property>
<!--Set集合的属性注入-->
<property name="set">
<set>
<value>ddd</value>
<value>eee</value>
<value>fff</value>
</set>
</property>
<!--Map集合的属性注入-->
<property name="map">
<map>
<entry key="aaa" value="111"/>
<entry key="bbb" value="222"/>
<entry key="ccc" value="333"/>
</map>
</property>
<!--Properties的属性注入-->
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">1234</prop>
</props>
</property>
</bean>
//*****4 SpringDemo类添加测试方法
@Test
public void demo4(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
CollectionBean collectionBean = (CollectionBean)applicationContext.getBean("collectionBean");
System.out.println(collectionBean);
}
}