Spring

一. Spring学习的核心内容

二. 快速入门

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!--1. 一个bean,就是一个java对象2. class属性用于指定类的全路径 ===> spring底层使用反射3. id属性表示改java对象在spring容器中的id,通过id可以获取到对象4. <property name="monsterId" value="100"></property> 用于给该对象属性赋值--><bean class="com.zzti.spring.entity.Monster" id="monster01"><property name="monsterId" value="100"></property><property name="monsterName" value="牛魔王"></property><property name="skill" value="芭蕉扇"></property></bean><bean class="com.zzti.spring.entity.Monster" id="monster02"><property name="monsterId" value="200"></property><property name="monsterName" value="孙悟空"></property><property name="skill" value="金箍棒"></property></bean></beans>
package com.zzti.spring.test;import com.zzti.spring.entity.Monster;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.io.File;public class SpringBootTest {@Testpublic void getMonster(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");//默认返回的是Object,但是运行类型是Monster//Object monster01 = applicationContext.getBean("monster01");//运行类型是= class com.zzti.spring.entity.Monster//System.out.println("monster01= " + monster01 +",运行类型是= "+ monster01.getClass());//System.out.println("monster01.name=" + monster01);//也可以直接类型强转Monster monster011 = (Monster) applicationContext.getBean("monster01");//monster011= Monster{monsterId=100, monsterName='牛魔王', skill='芭蕉扇'}System.out.println("monster011= " + monster011 );System.out.println("monster011.name=" + monster011.getMonsterName());//也可以在获取的时候,直接指定class类型Monster monster012 = applicationContext.getBean("monster01", Monster.class);System.out.println("monster012= " + monster012);}//2. 验证类加载路径@Testpublic void classPath(){File file = new File(this.getClass().getResource("/").getPath());//D:\Exercise_items\hsp_spring\target\classesSystem.out.println(file);}//3. 查看容器中注入了那些bean对象,会输出bean的id@Testpublic void getBeansId(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();for (String beanDefinitionName : beanDefinitionNames) {System.out.println("~~~" + beanDefinitionName);}}}

三. Spring容器结构/机制


  1. 在beanFactory下面有beanDefintionMap, beanDefintionMap类型是ConcurrentHashMap集合,其存放beans.xml中bean节点配置的bean对象的信息
  2. 在beanDefintionMap中有属性table,table是数组,类型是ConcurrentHashMap$Node。因为是数组,所以可以存放很多的bean对象信息,就是beans.xml配置。初始化是512,当超过时,会自动扩容。
  3. 通过hash算法,我们的Monster01对象的信息就保存在index=217的位置,保存是以ConcurrentHashMap$Node类型保存;key就是beans.xml中配置的id(monster01),value是monster01对象的信息[比如: 属性/属性值/类信息/是不是懒加载]
  4. propertyValues中记录的就是beans.xml中配置的monster01对象的属性名/属性值
  5. 在beanFactory中,有属性singletonObjects, 类型是ConcurrentHashMap;singletonObjects下面还有一个属性table,类型是ConcurrentHashMap$Node。如果你在beans.xml文件中配置的对象是 单例的 就会初始化在table中。
  6. 在beanFactory中,还有一个属性beanDefinitionNames。记录了我们在beans.xml中配置的bean名称,方便查找。

四. 手动开发简单的Spring基于XML配置的程序

  1. 需求说明
    自己写一个简单的Spring容器,通过读取beans.xml,获取第一个Javabean: Monster01对象,并给该对象属性赋值,放入到容器中,输出该对象信息。
  2. 思路分析
  3. 完成步骤
package com.zzti.spring.applicationcontext;
/*** 这个程序用于实现spring的一个简单容器机制, 后面会有详细的实现* 这里我们实现如何将beans.xml文件进行解析, 并生成对象,放入容器中* 提供一个getBean(id),返回对应的对象* 来简单的理解一下spring容器的机制*/
public class SpringApplicationContext {private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();//接收一个容器的配置文件(beans.xml),该文件默认放在src下面public SpringApplicationContext(String iocBeanXmlFile) throws Exception {//1. 得到类加载的路径String path = this.getClass().getResource("/").getPath();//path= /D:/Exercise%20items/hsp_spring/target/classes/System.out.println("path decode前= " + path);//添加如下代码,不然系统找不到path路径path = java.net.URLDecoder.decode(path, "utf-8");//path decode后= /D:/Exercise items/hsp_spring/target/classes/System.out.println("path decode后= " + path);//2. 创建saxReaderSAXReader saxReader = new SAXReader();//3. 得到document对象Document document = saxReader.read(new File(path + iocBeanXmlFile));//4. 得到rootDocumentElement rootElement = document.getRootElement();//5. 得到第一个bean(monster01)Element bean = (Element) rootElement.elements("bean").get(0);//6. 得到第一个bean的相关属性String id = bean.attributeValue("id");String classFullPath = bean.attributeValue("class");List<Element> property = bean.elements("property");//获取到相关属性值Integer monsterId = Integer.parseInt(property.get(0).attributeValue("value"));String monsterName = property.get(1).attributeValue("value");String skill = property.get(2).attributeValue("value");//7. 使用反射,创建对象Class<?> aClass = Class.forName(classFullPath);// 这里 o 对象就是Monster对象Monster o = (Monster) aClass.newInstance();//给 o 对象赋值, 通过反射中的setter方法来赋值的,这里就简写Method[] declaredMethods = aClass.getDeclaredMethods();o.setMonsterId(monsterId);o.setMonsterName(monsterName);o.setSkill(skill);//将床架好的对象,放入到ConcurrentHashMap中的singletonObjectssingletonObjects.put(id,o);}public Object getBean(String id){return singletonObjects.get(id);}
}
package com.zzti.spring.test;import com.zzti.spring.applicationcontext.SpringApplicationContext;
import com.zzti.spring.entity.Monster;public class SpringApplicationContextTest {public static void main(String[] args) throws Exception {SpringApplicationContext springApplicationContext =new SpringApplicationContext("beans.xml");Monster monster01 = (Monster) springApplicationContext.getBean("monster01");System.out.println("monster01= " + monster01);System.out.println("monster01.Name= " + monster01.getMonsterName());System.out.println("monster01.Skill= " + monster01.getSkill());System.out.println("ok~~");}
}

问题1: 假如没有在beans.xml文件中分配id,运行时会不会报错?
不会报错,能正常运行;系统会默认分配id,分配规则是: 全类名+#+数字

package com.zzti.spring.homework;import com.zzti.spring.entity.Monster;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class HomeWork01 {@Testpublic void getMonster(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster monster01 = applicationContext.getBean("com.zzti.spring.entity.Monster#0", Monster.class);System.out.println("monster01= " + monster01);System.out.println("monster01.minsterId= " + monster01.getMonsterId());Monster monster02 = applicationContext.getBean("com.zzti.spring.entity.Monster#1", Monster.class);System.out.println("monster02= " + monster02);System.out.println("monster02.minsterId= " + monster02.getMonsterId());System.out.println("测试没有分配id的情况~~~ok~~");}
}
========================测试结果================================
monster01= Monster{monsterId=100, monsterName='牛魔王', skill='芭蕉扇'}
monster01.minsterId= 100
monster02= Monster{monsterId=200, monsterName='孙悟空', skill='金箍棒'}
monster02.minsterId= 200
测试没有分配id的情况~~~ok~~

五. Spring配置/管理bean介绍

1. Bean管理包括两方面

创建bean对象
给bean注入属性

2.Bean配置方式

基于XML文件配置方式
基于注解方式

3. 介绍基于XML配置bean
3.1 通过类型来获取bean
 <bean class="com.zzti.spring.entity.Monster" id="monster01"><property name="monsterId" value="100"></property><property name="monsterName" value="牛魔王"></property><property name="skill" value="芭蕉扇"></property></bean>
@Test
public void getMonsterByType(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster monster = applicationContext.getBean(Monster.class);System.out.println("monster= " + monster);
}
=======================================
monster= Monster{monsterId=100, monsterName='牛魔王', skill='芭蕉扇'}
注意细节:按类型来获取bean,要求IOC容器中的同一个类的bean只能有一个,否则会抛出异常(bean不唯一)
这种方式的应用场景: 比如:xxxAction/xxxServlet/xxxController,或者xxxService;在一个线程中只需要一个对象实例(单例)的情况在容器配置文件(beans.xml)中给属性赋值,底层是通过setter()完成的,这也是为什么我们需要提供setter()的原因。
3.2 通过构造器配置bean
<!--通过构造器来配置bean--><bean id="monster03" class="com.zzti.spring.entity.Monster"><constructor-arg value="2" index="0"></constructor-arg><constructor-arg value="蜘蛛精" index="1"></constructor-arg><constructor-arg value="吐口水" index="2"></constructor-arg></bean><bean id="monster031" class="com.zzti.spring.entity.Monster"><constructor-arg value="3" type="java.lang.Integer"></constructor-arg><constructor-arg value="白骨精" type="java.lang.String"></constructor-arg><constructor-arg value="白骨鞭" type="java.lang.String"></constructor-arg></bean>
@Test
public void getMonsterByConstructor(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster monster03 = (Monster) applicationContext.getBean("monster03");Monster monster031 = (Monster) applicationContext.getBean("monster031");System.out.println("monster03= " + monster03);System.out.println("monster031= " + monster031);
}
=====================================================
monster03= Monster{monsterId=2, monsterName='蜘蛛精', skill='吐口水'}
monster031= Monster{monsterId=3, monsterName='白骨精', skill='白骨鞭'}
使用细节:1. 通过index属性来区分是第几个参数2. 通过type属性来区分是什么类型(按照顺序)
3.3 通过P名称空间配置bean
xmlns:p="http://www.springframework.org/schema/p"
<!--通过P命名空间来配置bean-->
<bean id="monster06" class="com.zzti.spring.entity.Monster"p:monsterId="600" p:monsterName="红孩儿" p:skill="三味真火" />
@Test
public void getMonsterForP(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster monster06 = (Monster) applicationContext.getBean("monster06");System.out.println("monster06= " + monster06);
}
3.4 通过ref引用 / 注入其他bean对象
<!--通过ref引用 / 注入其他bean对象-->
<bean id="memberServiceImpl" class="com.zzti.spring.service.MemberServiceImpl"><!--ref表示memberDao这个属性将引用或指向id=memberDaoImpl对象--><property name="memberDao" ref="memberDaoImpl"></property>
</bean>
<bean id="memberDaoImpl" class="com.zzti.spring.dao.MemberDaoImpl"></bean>
@Test
public void getBeanByRef(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");MemberServiceImpl memberServiceImpl = applicationContext.getBean("memberServiceImpl", MemberServiceImpl.class);memberServiceImpl.add();
}
===============================================
MemberServiceImpl 无参构造器~~
MemberDaoImpl 无参构造器~~
MemberServiceImpl add()方法
MemberDaoImpl add()方法~~
3.5 引用 / 注入内部bean对象
 <!--通过property注入内部bean对象, 直接在配置bean时注入--><bean id="memberServiceImpl02" class="com.zzti.spring.service.MemberServiceImpl"><property name="memberDao"><bean class="com.zzti.spring.dao.MemberDaoImpl"></bean></property></bean>
@Test
public void getBeanByProperty(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");MemberServiceImpl memberServiceImpl02 = applicationContext.getBean("memberServiceImpl02", MemberServiceImpl.class);memberServiceImpl02.add();
}
=========================================================
MemberServiceImpl 无参构造器~~
MemberDaoImpl 无参构造器~~
MemberServiceImpl 无参构造器~~
MemberDaoImpl 无参构造器~~
MemberServiceImpl add()方法
MemberDaoImpl add()方法~~
3.6 引用 / 注入 集合/ 数组类型
<!--给集合属性注入值--><bean id="master01" class="com.zzti.spring.entity.Master"><property name="name" value="太上老君"></property><!--给bean对象的list集合赋值--><property name="monsterList"><list><ref bean="monster02"></ref><ref bean="monster03"></ref></list></property><!--给bean对象的map集合赋值--><property name="monsterMap"><map><entry><key><value>monsterKey01</value></key><ref bean="monster01"></ref></entry><entry><key><value>monsterKey02</value></key><ref bean="monster031"></ref></entry></map></property><!--给bean对象的properties集合赋值--><property name="pros"><props><prop key="k1">Java工程师</prop><prop key="k2">前端工程师</prop><prop key="k3">大数据工程师</prop></props></property><!--给bean对象的数组属性赋值--><property name="monsterName"><array><value>金角大王</value><value>银角大王</value></array></property><!--给bean对象的set属性赋值--><property name="monsterSet"><set><ref bean="monster01"></ref><bean class="com.zzti.spring.entity.Monster"><property name="monsterId" value="123"></property><property name="monsterName" value="玉兔精"></property><property name="skill" value="吃唐僧肉"></property></bean></set></property></bean>
@Test
public void setCollectionByProperty(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Master master01 = applicationContext.getBean("master01", Master.class);//获取list集合System.out.println("===============list==================");List<Monster> monsterList = master01.getMonsterList();for (Monster monster : monsterList) {System.out.println("获取list= " + monster);}//获取map集合System.out.println("===========map====================");Map<String, Monster> monsterMap = master01.getMonsterMap();Set<Map.Entry<String, Monster>> entrySet = monsterMap.entrySet();for (Map.Entry<String, Monster> entry : entrySet) {System.out.println("获取map中entry= " + entry);}//获取propertiesSystem.out.println("=============properties====================");Properties pros = master01.getPros();String property1 = pros.getProperty("k1");String property2 = pros.getProperty("k2");String property3 = pros.getProperty("k3");System.out.println(property1 +"\t"+ property2 +"\t"+ property3);//获取数组System.out.println("=============数组======================");String[] monsterName = master01.getMonsterName();for (String s : monsterName) {System.out.println("妖怪名称= " + s);}//获取setSystem.out.println("=================set==============");Set<Monster> monsterSet = master01.getMonsterSet();for (Monster monster : monsterSet) {System.out.println("monsterSet= " + monster);}
}
===============list==================
获取list= Monster{monsterId=200, monsterName='孙悟空', skill='金箍棒'}
获取list= Monster{monsterId=2, monsterName='蜘蛛精', skill='吐口水'}
===========map====================
获取map中entry= monsterKey01=Monster{monsterId=100, monsterName='牛魔王', skill='芭蕉扇'}
获取map中entry= monsterKey02=Monster{monsterId=3, monsterName='白骨精', skill='白骨鞭'}
=============properties====================
Java工程师 前端工程师   大数据工程师
=============数组======================
妖怪名称= 金角大王
妖怪名称= 银角大王
=================set==============
monsterSet= Monster{monsterId=100, monsterName='牛魔王', skill='芭蕉扇'}
monsterSet= Monster{monsterId=123, monsterName='玉兔精', skill='吃唐僧肉'}
注意细节:1. 主要掌握List/Map/Properties三种集合的使用2. Properties集合的特点。properties是hashtable的子类,是key-value的形式;key和value都是string
3.7 通过util名称空间创建bean
<!--通过util名称空间来创建list集合,可以当做创建bean对象的工具来使用--><util:list id="myBookList"><value>三国演义</value><value>西游记</value><value>红楼梦</value><value>水浒传</value></util:list><bean id="book" class="com.zzti.spring.entity.Book"><property name="bookList" ref="myBookList"></property></bean>
@Test
public void getListByUtil() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Book book = applicationContext.getBean("book", Book.class);List<String> bookList = book.getBookList();for (String s : bookList) {System.out.println("bookList= " + s);}
}
=====================================================
bookList= 三国演义
bookList= 西游记
bookList= 红楼梦
bookList= 水浒传
3.8 级联属性赋值(直接给对象的属性赋值)
 <!--级联属性赋值--><bean id="emp" class="com.zzti.spring.entity.Emp"><property name="name" value="pt"></property><property name="dept" value="dept"></property><property name="dept.name" value="java开发部"></property></bean><bean id="dept" class="com.zzti.spring.entity.Dept"></bean>
@Testpublic void setProByRelation() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Emp emp = applicationContext.getBean("emp", Emp.class);System.out.println("emp.dept= " + emp.getDept().getName());System.out.println("emp.name= " + emp.getName());}
==========================================================
emp.dept= java开发部
emp.name= pt
3.9 通过静态工厂获取对象
<!--通过静态工厂来获取bean对象--><!--1. class是静态工厂的路径2. factory-method 表示是指定静态工厂类的那个方法返回对象3. constructor-arg value="monster_01", value是指定要返回静态工厂的那个对象-->
<bean id="staticFactory_monster" class="com.zzti.spring.factory.MyStaticFactory" factory-method="getMonster"><!--constructor-arg标签提供key--><constructor-arg value="monster_01"></constructor-arg></bean>
package com.zzti.spring.factory;import com.zzti.spring.entity.Monster;import java.util.HashMap;
import java.util.Map;public class MyStaticFactory {private static Map<String, Monster> monsterMap;static {monsterMap = new HashMap<String,Monster>();monsterMap.put("monster_01",new Monster(100,"欧阳修","蛤蟆功"));monsterMap.put("monster_02",new Monster(200,"黄老邪","打狗棒"));}public static Monster getMonster(String key){return monsterMap.get(key);}}
====================================================================
@Test
public void getBeanByStaticFactory(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster my_monster = applicationContext.getBean("staticFactory_monster", Monster.class);System.out.println("my_monster= " + my_monster);
}
============================================================
my_monster= Monster{monsterId=200, monsterName='黄老邪', skill='打狗棒'}
3.10 通过实例工厂获取对象
<!--通过实例工厂来获取bean对象--><bean id="instanceFactory" class="com.zzti.spring.factory.MyInstanceFactory"></bean><!--1. factory-bean 指定使用那个实例工厂对象返回bean2. factory-method 指定使用实例工厂对象的那个方法返回bean3. constructor-arg value="monster_03" 指定获取到实例工厂中那个对象--><bean id="my_monster" factory-bean="instanceFactory" factory-method="getMonster"><constructor-arg value="monster_03"></constructor-arg></bean>
package com.zzti.spring.factory;import com.zzti.spring.entity.Monster;import java.util.HashMap;
import java.util.Map;public class MyInstanceFactory {private Map<String, Monster> monsterMap;{monsterMap = new HashMap<String,Monster>();monsterMap.put("monster_03",new Monster(300,"欧阳修2","蛤蟆功"));monsterMap.put("monster_04",new Monster(400,"黄老邪2","打狗棒"));}//提供一个方法,返回Monster对象public  Monster getMonster(String key){return monsterMap.get(key);}
}
=======================================================
@Test
public void getBeanByInstanceFactory(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster my_monster = applicationContext.getBean("my_monster", Monster.class);System.out.println("my_monster= " + my_monster);
}
========================================================
my_monster= Monster{monsterId=300, monsterName='欧阳修2', skill='蛤蟆功'}

注意事项:

静态工厂时: 当创建两个对象(my_monster,my_monster02)时,在分别调用staticFactory_monster与staticFactory_monster02时,同时这两个bean中constructor-arg调用的是同一个对象,这两个是同一个对象。也就是my_monster == my_monster02
同理当实例工厂时,也是分别调用两个bean时,创建的两个对象是不一样的。
因为静态工厂创建的是静态类,静态类是不会改变的。
<bean id="staticFactory_monster" class="com.zzti.spring.factory.MyStaticFactory" factory-method="getMonster"><!--constructor-arg标签提供key--><constructor-arg value="monster_02"></constructor-arg>
</bean>
<bean id="staticFactory_monster02" class="com.zzti.spring.factory.MyStaticFactory" factory-method="getMonster"><!--constructor-arg标签提供key--><constructor-arg value="monster_02"></constructor-arg>
</bean>
Monster my_monster = applicationContext.getBean("staticFactory_monster", Monster.class);
Monster my_monster02 = applicationContext.getBean("staticFactory_monster02", Monster.class);
System.out.println(my_monster == my_monster02 );//true
3.11 通过FactoryBean获取对象(重点)
<!--通过FactoryBean来获取bean对象--><!--1. class 表示 指定使用的是那个FactoryBean2. key 表示就是MyFactoryBean 属性key3. value 就是你要获取的对象对应的key--><bean id="factoryBean" class="com.zzti.spring.factory.MyFactoryBean"><property name="key" value="monster_06"></property></bean>
package com.zzti.spring.factory;import com.zzti.spring.entity.Monster;
import org.springframework.beans.factory.FactoryBean;import java.util.HashMap;
import java.util.Map;public class MyFactoryBean implements FactoryBean<Monster> {private String key;private Map<String, Monster> monsterMap;{monsterMap = new HashMap<String,Monster>();monsterMap.put("monster_05",new Monster(500,"欧阳修3","蛤蟆功"));monsterMap.put("monster_06",new Monster(600,"黄老邪3","打狗棒"));}public void setKey(String key) {this.key = key;}@Overridepublic Monster getObject() throws Exception {return monsterMap.get(key);}@Overridepublic Class<?> getObjectType() {return Monster.class;}@Overridepublic boolean isSingleton() {return true;}
}
===========================================================
@Test
public void getBeanByFactoryBean(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster factoryBean = applicationContext.getBean("factoryBean", Monster.class);System.out.println("factoryBean= " + factoryBean);
}
3.11 通过继承配置bean
<!--通过继承配置bean--><bean id="monster_bean"class="com.zzti.spring.entity.Monster"parent="monster02"></bean><bean class="com.zzti.spring.entity.Monster" id="monster02"><property name="monsterId" value="200"></property><property name="monsterName" value="孙悟空"></property><property name="skill" value="金箍棒"></property></bean><!--若bean指定了abstract="true",表示该bean对象用于被继承,本身这个bean不能被获取(实例化)--><bean id="monster_bean02" class="com.zzti.spring.entity.Monster" abstract="true"><constructor-arg value="2" index="0"></constructor-arg><constructor-arg value="蜘蛛精~" index="1"></constructor-arg><constructor-arg value="吐口水~" index="2"></constructor-arg></bean><bean id="monster_bean03" class="com.zzti.spring.entity.Monster" parent="monster_bean02">
@Test
public void getBeanByExtends(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Monster monster_bean = applicationContext.getBean("monster_bean", Monster.class);System.out.println("monster_bean= " + monster_bean);//Monster monster_bean02 = applicationContext.getBean("monster_bean02", Monster.class);//Error creating bean with name 'monster_bean02': Bean definition is abstract//System.out.println("monster_bean02= " + monster_bean02);Monster monster_bean03 = applicationContext.getBean("monster_bean03", Monster.class);System.out.println("monster_bean03= " + monster_bean03);}
======================================================================
monster_bean= Monster{monsterId=200, monsterName='孙悟空', skill='金箍棒'}
monster_bean03继承monster_bean02时输出结果:
monster_bean= Monster{monsterId=200, monsterName='孙悟空', skill='金箍棒'}
monster_bean03= Monster{monsterId=2, monsterName='蜘蛛精~', skill='吐口水~'}

六. Bean创建顺序

<!--bean的黄建顺序-->
<bean id="student" class="com.zzti.spring.entity.Student" depends-on="department"></bean>
<bean id="department" class="com.zzti.spring.entity.Department"></bean>
默认情况下, bean的创建顺序是按照xml文件中配置的顺序创建,但是若加上depends-on属性,则就根据depends-on="xxx"先创建, 再创建其本身。
@Test
public void testBeanByCreate(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");System.out.println("ok~~~");
}

引出一个问题:

1. 如下的两个bean创建的顺序是什么?
<bean id="memberServiceImpl" class="com.zzti.spring.service.MemberServiceImpl"><property name="memberDao" ref="memberDaoImpl"></property>
</bean>
<bean id="memberDaoImpl" class="com.zzti.spring.dao.MemberDaoImpl"></bean>
执行流程:
2. 先创建id="memberServiceImpl"
3. 再创建id="memberDaoImpl"
4. 用memberServiceImpl,setMemeberDao(),完成引用
==========================================================
<bean id="memberDaoImpl" class="com.zzti.spring.dao.MemberDaoImpl"></bean>
<bean id="memberServiceImpl" class="com.zzti.spring.service.MemberServiceImpl"><property name="memberDao" ref="memberDaoImpl"></property>
</bean>
执行流程:
1. 先创建id="memberDaoImpl"
2. 再创建id="memberServiceImpl"
3. 用memberServiceImpl,setMemeberDao(),完成引用

七. Bean对象的单例和多例

<!--bean的单例和多例-->
<!--1. 在默认情况下, scope属性是singleton2. 在applicationContext容器中只有这一个对象3. 当执行getBean()时, 返回的是同一个对象4. 如果我们希望每一次返回一个新的对象,则可以scope="prototype"
-->
<bean id="cat" class="com.zzti.spring.entity.Cat" scope="prototype" ><property name="id" value="100"></property><property name="name" value="小花猫"></property>
</bean>
@Test
public void testBeanByScope(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");Cat cat = applicationContext.getBean("cat", Cat.class);Cat cat1 = applicationContext.getBean("cat", Cat.class);Cat cat2 = applicationContext.getBean("cat", Cat.class);/*** 加上scope="prototype"* cat= com.zzti.spring.entity.Cat@5db6b9cd* cat1= com.zzti.spring.entity.Cat@210ab13f* cat2= com.zzti.spring.entity.Cat@20b2475a* =====================================================* 默认情况下是scope="singleton",可省略不写* cat= com.zzti.spring.entity.Cat@6f43c82* cat1= com.zzti.spring.entity.Cat@6f43c82* cat2= com.zzti.spring.entity.Cat@6f43c82*/System.out.println("cat= " + cat);System.out.println("cat1= " + cat1);System.out.println("cat2= " + cat2);System.out.println("ok~~~");
}

注意事项:
1. 默认是单列singleton,在启动容器时,默认就会创建,并放入到singletonObject集合
2. 当设置scope="prototype"为多实例机制后,该bean是在getBean()时才创建
3. 如果是单例singleton,同时希望在getBean时才创建,可以指定懒加载lazy-init=“true”(默认是false)
4. 通常情况下,lazy-init就使用默认值false,在开发来看,使用空间换时间是值得的,除非是有特殊的要求
5. 如果scope=“prototype”。这时你的lazy-init属性的值,不管是true还是false都是在getBean时候,才创建对象

八. Bean对象的生命周期

bean对象创建是由JVM完成的,然后执行方法如下:

  1. 执行构造器
  2. 执行set相关的方法
  3. 调用bean的初始化的方法(需要配置)
  4. 使用bean
  5. 当容器关闭时,调用bean的销毁方法(需要配置)
 <!--演示bean的生命周期--><bean id="house" class="com.zzti.spring.entity.House"init-method="init" destroy-method="destroy"><property name="name" value="汤臣一品"></property></bean>
package com.zzti.spring.entity;public class House {private String name;public House() {System.out.println("House 的无参构造函数执行~~");
}public House(String name) {this.name = name;
}public String getName() {return name;
}public void setName(String name) {System.out.println("House setName()=" + name);this.name = name;
}public void init(){System.out.println("House init()执行~~");
}public void destroy(){System.out.println("House destroy()执行~~");
}@Override
public String toString() {return "House{" +"name='" + name + '\'' +'}';
}
}
@Test
public void testBeanByLife() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");House house = applicationContext.getBean("house", House.class);System.out.println("house= " + house);applicationContext.close();/*** 注意细节:* 1) 初始化init() 和 destroy() 是需要程序员自己指定的* 2) destroy()就是当容器关闭时, 才会被调用* =========================================* House 的无参构造函数执行~~* House setName()=汤臣一品* House init()执行~~* house= House{name='汤臣一品'}* House destroy()执行~~*/
}

九. 配置Bean的后置处理器(难点)

  1. 在spring的IOC容器, 可以配置bean的后置处理器
  2. 该处理器/对象会在 bean初始化方法调用前bean初始化方法调用后被调用
  3. 程序员可以在后置处理器中编写自己的代码
<!--演示配置bean的后置处理器-->
<bean id="house" class="com.zzti.spring.entity.House"init-method="init" destroy-method="destroy"><property name="name" value="大豪宅"></property>
</bean><bean id="house02" class="com.zzti.spring.entity.House"init-method="init" destroy-method="destroy"><property name="name" value="北京豪宅"></property>
</bean><!--配置bean的后置处理器-->
<bean id="myBeanPostProcessor" class="com.zzti.spring.entity.MyBeanPostProcessor"></bean>
package com.zzti.spring.entity;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {/*** 在bean初始化之前完成某些任务* @param bean 就是IOC容器返回的bean对象, 如果这里被替换会修改,则返回的bean对象也会被修改* @param beanName 就是IOC容器配置的bean的名称* @return 就是返回的bean对象* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization....bean= " + bean +"beanName= " + beanName);//如果bean是house类型,就把所有的bean改成 上海豪宅if (bean instanceof House) {((House) bean).setName("上海豪宅");}return bean;}/*** 在bean初始化之后完成某些任务* @param bean 就是IOC容器返回的bean对象, 如果这里被替换会修改,则返回的bean对象也会被修改* @param beanName 就是IOC容器配置的bean的名称* @return 就是返回的bean对象* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization....bean= " + bean +"beanName= " + beanName);return bean;}
}
@Test
public void getBeanByPostProcess(){ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");House house = ioc.getBean("house", House.class);System.out.println("house= " + house);/*** 注意这里的写法* ApplicationContext(是一个接口) 是编译类型; ClassPathXmlApplicationContext试运行类型* (ClassPathXmlApplicationContext)ioc ==> ApplicationContext*/((ClassPathXmlApplicationContext)ioc).close();/*** 执行结果如下:* House 的无参构造函数执行~~* House setName()=大豪宅* postProcessBeforeInitialization....bean= House{name='大豪宅'}beanName= house* House setName()=上海豪宅* House init()执行~~* postProcessAfterInitialization....bean= House{name='上海豪宅'}beanName= house* House 的无参构造函数执行~~* House setName()=北京豪宅* postProcessBeforeInitialization....bean= House{name='北京豪宅'}beanName= house02* House setName()=上海豪宅* House init()执行~~* postProcessAfterInitialization....bean= House{name='上海豪宅'}beanName= house02* house= House{name='上海豪宅'}* House destroy()执行~~* House destroy()执行~~*/
}

其他说明:

  1. 怎么执行到这个方法(postProcessBeforeInitialization / postProcessAfterInitialization) ===> 使用AOP[反射+动态代理+IO+容器+注解]
  2. 有什么用?===> 可以对IOC容器中所有的对象进行统一处理,比如: 日志处理/权限的校验/安全的验证/事务管理
  3. 针对容器的所有的对象吗? ===> 是的,切面编程

十. 通过属性文件给bean注入值

my.properties

monsterId=300
#中文转Unicode编码
monsterName=\u4e4c\u9f9f\u7cbe
skill=\u7f29\u8116\u5b50
<!--通过属性文件给bean注入值-->
<context:property-placeholder location="classpath:my.properties" /><bean id="monsterByFile" class="com.zzti.spring.entity.Monster"><property name="monsterId" value="${monsterId}"></property><property name="monsterName" value="${monsterName}"></property><property name="skill" value="${skill}"></property></bean>
@Test
public void setBeanByFile(){ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster monsterByFile = ioc.getBean("monsterByFile", Monster.class);System.out.println("monsterByFile= " + monsterByFile);
}
=========================================
monsterByFile= Monster{monsterId=300, monsterName='乌龟精', skill='缩脖子'}

十一. 基于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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="orderDao" class="com.zzti.spring.dao.OrderDao"></bean><!--基于xml的bean的自动转配1. autowire="byType"方式. 表示根据类型进行自动转配,这里就是在创建orderService时,通过类型的方式 给对象属性 自动完成赋值 / 引用比如OrderService 对象有 private OrderDao orderDao,就会在容器中去找有没有OrderDao类型对象如果有, 就会自动装配. 但是在这里容器中,不能有两个orderDao对象, 否则就会找不到若class类对象中没有属性, autowire就没有必要写2. autowire="byName"方式. 会自动去找id为setXxxx,后面的Xxxx的bean自动组装,如果找到就装配,如果找不到就会报错比如这里的: <bean id="orderController" autowire="byType" class="com.zzti.spring.controller.OrderController"/>就会找OrderController中定义的setOrderService的id="orderService"的OrderServicebean找到就组装,找不到就组装失败--><bean id="orderService" autowire="byType" class="com.zzti.spring.service.OrderService"></bean><bean id="orderController" autowire="byType" class="com.zzti.spring.controller.OrderController"></bean></beans>
public class OrderDao {public void saveOrder(){System.out.println("保存一个订单~~");}
}
public class OrderService {private OrderDao orderDao;public OrderDao getOrderDao() {return orderDao;}public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}
}
public class OrderController {private OrderService orderService;public OrderService getOrderService() {return orderService;}public void setOrderService(OrderService orderService) {this.orderService = orderService;}
}
@Test
public void setBeanByAutowire(){ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");OrderController orderController = ioc.getBean("orderController", OrderController.class);orderController.getOrderService().getOrderDao().saveOrder();}
===============================================================
保存一个订单~~

十二. Spring的EL表达式(知道即可)

  1. SpEL和EL表达式一样, SpEL根据Javabean风格的getXxx()、setXxx()方法定义的属性访问对象。
  2. SpEL使用#{…}作为定界符,所有在大括号中的字符都将被认为是SpEL表达式。
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean class="com.zzti.spring.entity.Monster" id="monster01"><property name="monsterId" value="100"></property><property name="monsterName" value="牛魔王"></property><property name="skill" value="芭蕉扇"></property></bean><bean class="com.zzti.spring.entity.Monster" id="monster02"><property name="monsterId" value="200"></property><property name="monsterName" value="孙悟空"></property><property name="skill" value="金箍棒"></property></bean><bean id="spELBean" class="com.zzti.spring.entity.SpELBean"><!--sp el给自变量--><property name="name" value="#{'韩顺平教育'}"></property><!--引用其他bean--><property name="monster" value="#{monster01}"></property><!--引用其他bean的属性值--><property name="monsterName" value="#{monster02.monsterName}"></property><!--调用普通方法--><property name="crySound" value="#{spELBean.cry('喵喵的...')}"></property><!--调用静态方法--><property name="bookName" value="#{T(com.zzti.spring.entity.SpELBean).read('天龙八部')}"></property><!--通过运算赋值--><property name="result" value="#{5*8}"></property></bean></beans>
package com.zzti.spring.entity;public class SpELBean {private String name;private Monster monster;private String monsterName;private String crySound;private String bookName;private Double result;public SpELBean() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public Monster getMonster() {return monster;}public void setMonster(Monster monster) {this.monster = monster;}public String getMonsterName() {return monsterName;}public void setMonsterName(String monsterName) {this.monsterName = monsterName;}public String getCrySound() {return crySound;}public void setCrySound(String crySound) {this.crySound = crySound;}public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public Double getResult() {return result;}public void setResult(Double result) {this.result = result;}public String cry(String sound){return "发出" + sound + "叫声...";}public static String read(String bookName){return "正在看 " + bookName;}
}
@Test
public void setBeanBySpEL(){ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);System.out.println(spELBean.getName());System.out.println(spELBean.getMonster());System.out.println(spELBean.getMonsterName());System.out.println(spELBean.getCrySound());System.out.println(spELBean.getBookName());System.out.println(spELBean.getResult());
}

Spring----Spring容器机制+Spring配置bean相关推荐

  1. 4. Spring 如何通过 XML 文件配置Bean,以及如何获取Bean

    在 Spring 容器内拼凑 bean 叫做装配.装配 bean 的时候,你是在告诉容器,需要哪些 bean ,以及容器如何使用依赖注入将它们配合在一起. 理论上,bean 装配的信息可以从任何资源获 ...

  2. Spring基础18——通过注解配置bean之间的关联关系

    1.组件装配 <context:component-scan>元素还会自动注册AutowiredAnnotaionBeanPostProcessor实例,这是一个bean的后置处理器,该实 ...

  3. Spring 在xml文件中配置Bean

    Spring容器是一个大工厂,负责创建.管理所有的Bean. Spring容器支持2种格式的配置文件:xml文件.properties文件,最常用的是xml文件. Bean在xml文件中的配置 < ...

  4. Spring系列【11】配置Bean的初始化行为

    对某个Bean添加lazy-init属性:lazy-init 设置只对scop属性为singleton的bean起作用 1 <?xml version="1.0" encod ...

  5. Spring异常重试机制 - Spring Retry

    目录 一 . 引入依赖 二 . 在启用类或业务类上添加@EnableRetry注解启用重试机制(在启用类上添加全局有效 , 在业务类上添加仅当前有效) 三 . 使用@Retryable实现重试 四 . ...

  6. Spring IoC容器与Bean管理

    Spring IoC容器与Bean管理 一.Spring IoC容器与Bean管理 1.Spring快速入门 IoC控制反转 DI依赖注入 Spring概述 Spring IoC初体验 使用XML方式 ...

  7. Spring配置Bean的几种方式

    ​ Spring容器提供了三种装配bean的方式,所谓装配就是指将bean配置在spring容器中,并能够在类与类之间提供依赖关系. 一.隐式Bean发现机制和自动装配 ​ Spring从两个角度来实 ...

  8. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(6):Spring IOC容器学习(概念、作用、Bean生命周期)...

    一.IOC控制反转概念 控制反转(IOC)是一种通过描述(在Java中可以是XML或者是注解)并通过第三方去生产或获取特定对象的方式. 主动创建模式,责任在于开发者,而在被动模式下,责任归于Ioc容器 ...

  9. Spring是bean的容器,那么到底bean是什么,容器又在哪里。(bean存在spring的哪里)

    趁着金九跳槽季,跳槽成功了.从之前的老东家跳入很老的大厂,也算完成了自己的大场梦.按照自己迂腐思想,两三年内应该不会跳槽了.所以希望静下心来搞搞基础,而不再是各种面试突击了.面试突击虽好,但总感觉根基 ...

  10. JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试

    Spring框架学习路线 Spring的IOC Spring的AOP,AspectJ Spring的事务管理,三大框架的整合 Spring框架概述 什么是Spring?  Spring是分层的Java ...

最新文章

  1. 安装完Visual Team System 2008 Team Explorer出错解决办法
  2. Ubuntu 下载安装删除方式(自己常用,保持更新)
  3. 02-初识CoreData
  4. java 中断代码_你的java代码可中断吗?(2)
  5. android 获取已安装应用的安装包,Android获取设备已安装的应用
  6. iphone数据迁移到新iphone_iphone数据丢失?想要恢复iphone丢失的数据?
  7. 安装i3_330mm长显卡,240水冷,我的第一款小钢炮,雷匠R-i3装机体验
  8. javascript无提示关闭窗口,兼容IE,Firefox
  9. hql中 oracle当前时间,hql oracle 比较 日期时间
  10. LaTeX组件:texlive2019+texstudio+sumatraPDF 安装包及学习手册
  11. 1. 喵喵宠物管理系统需求分析
  12. Python脚本之批量重命名文件
  13. ANSI颜色使用研究 (转)
  14. dax和m的区别_DAX:一文透彻理解DAX本质
  15. 女生到社会上会遇到比学校更优秀的男生,而男生很难找到比在学校更好的女生。是吗?
  16. STM32F103的AD采样非线性问题
  17. Zabbix 主动/被动 监控
  18. Zhong__Centos安装Redis
  19. 超级基金投资术 用10万赚100万!
  20. 【硬十宝典】——1.2【基础知识】开关电源各种拓扑结构的特点

热门文章

  1. 【光波电子学】绪论-基本概念
  2. 机器学习讲堂 监督学习,无监督学习,弱监督学习,无监督学习
  3. kali源更新文件尺寸不符解决办法
  4. 深入理解javascript系列(十五):高阶函数
  5. linux内核中的信号机制--信号机制的管理结构
  6. 学计算机的心态,计算机专业考前心态调整
  7. 善变的“度娘”,周珍依然爱你
  8. 用Nginx服务器做网站
  9. 前端实习第4天--支付宝小程序事件绑定及组件传值
  10. 使用 OpenSSL 创建自签名证书