1.创建bean对象
2.给bean注入属性
1.基于xml文件配置方式
2.基于注解方式
<bean class="com.llp.spring.bean.Monster">
<property name="monsterId" value="3"/>
<property name="name" value="琪琪"/>
<property name="skill" value="魅惑"/>
bean>
@Test
public void getBeanByType(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
//通过类型获取bean,要求 ioc 容器中的同一个类的 bean 只能有一个!!
Monster bean = ioc.getBean(Monster.class);
System.out.println(bean);
}
1、按类型来获取 bean, 要求 ioc 容器中的同一个类的 bean 只能有一个, 否则会抛出异常
org.springframework.beans.NotWritablePropertyException: Invalid property ‘skill’ of bean class [com.llp.spring.bean.Monster]: Bean property ‘skill’ is not writable or has an invalid setter method.
2、这种方式的应用场景:比如 XxxAction/Servlet/Controller, 或 XxxService 在一个线程
3、在容器配置文件(比如 beans.xml)中给属性赋值, 底层是通过setter 方法完成的, 这也是为什么我们需要提供 setter 方法的原因
beans.xml
<bean class="com.llp.spring.bean.Monster" id="monster03">
<constructor-arg value="4" index="0"/>
<constructor-arg value="白骨精" index="1"/>
<constructor-arg value="吸血" index="2"/>
bean>
<bean class="com.llp.spring.bean.Monster" id="monster04">
<constructor-arg value="5" name="monsterId"/>
<constructor-arg value="蜘蛛精" name="name"/>
<constructor-arg value="吸血" name="skill"/>
bean>
<bean class="com.llp.spring.bean.Monster" id="monster05">
<constructor-arg value="6" type="java.lang.Integer"/>
<constructor-arg value="黑熊精" type="java.lang.String"/>
<constructor-arg value="掏心" type="java.lang.String"/>
bean>
@Test
public void getBeanByConstructor(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster03 = ioc.getBean("monster03",Monster.class);
System.out.println(monster03);
Monster monster04 = ioc.getBean("monster04",Monster.class);
System.out.println(monster04);
Monster monster05 = ioc.getBean("monster05",Monster.class);
System.out.println(monster05);
}
<bean class="com.llp.spring.bean.Monster" id="monster06"
p:monsterId="6"
p:name="红孩儿"
p:skill="三味真火"
/>
@Test
public void getBeanByPNameSpace(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean = ioc.getBean("monster06",Monster.class);
System.out.println(bean);
}
beans.xml
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService" p:memberDao-ref="memberDao">
bean>
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
//通过ref来设置bean属性
@Test
public void setBeanByRef(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);
memberService.add();
}
<bean class="com.llp.spring.dao.MemberDaoImpl" id="memberDao"/>
<bean class="com.llp.spring.service.MemberServiceImpl" id="memberService2">
<property name="memberDao">
<bean class="com.llp.spring.dao.MemberDaoImpl"/>
property>
bean>
/**
* 通过内部bean设置属性
*/
@Test
public void setBeanByPro(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
MemberServiceImpl memberService = ioc.getBean("memberService2", MemberServiceImpl.class);
memberService.add();
}
Master.java实体类
public class Master {
private String name;//主人名
private List<Monster> monsterList;
private Map<String, Monster> monsterMap;
private Set<Monster> monsterSet;
//数组
private String[] monsterName;
//Java基础
//这个Properties 是 Hashtable的子类 , 是key-value的形式
//这里Properties key和value 都是String
private Properties pros;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Monster> getMonsterList() {
return monsterList;
}
public void setMonsterList(List<Monster> monsterList) {
this.monsterList = monsterList;
}
public Map<String, Monster> getMonsterMap() {
return monsterMap;
}
public void setMonsterMap(Map<String, Monster> monsterMap) {
this.monsterMap = monsterMap;
}
public Set<Monster> getMonsterSet() {
return monsterSet;
}
public void setMonsterSet(Set<Monster> monsterSet) {
this.monsterSet = monsterSet;
}
public String[] getMonsterName() {
return monsterName;
}
public void setMonsterName(String[] monsterName) {
this.monsterName = monsterName;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
@Override
public String toString() {
return "Master{" +
"name='" + name + '\'' +
", monsterList=" + monsterList +
", monsterMap=" + monsterMap +
", monsterSet=" + monsterSet +
", monsterName=" + Arrays.toString(monsterName) +
", pros=" + pros +
'}';
}
}
<bean class="com.llp.spring.bean.Master" id="master">
<property name="name" value="太上老君"/>
<property name="monsterList">
<list>
<ref bean="monster01"/>
<ref bean="monster02"/>
<bean class="com.llp.spring.bean.Monster">
<property name="name" value="老鼠精"/>
<property name="monsterId" value="100"/>
<property name="skill" value="吃粮食"/>
bean>
list>
property>
<property name="monsterMap">
<map>
<entry>
<key>
<value>monster03value>
key>
<ref bean="monster03"/>
entry>
<entry>
<key>
<value>monster04value>
key>
<ref bean="monster04"/>
entry>
map>
property>
<property name="monsterSet">
<set>
<ref bean="monster05"/>
<ref bean="monster06"/>
<bean class="com.llp.spring.bean.Monster">
<property name="name" value="金角大王"/>
<property name="skill" value="吐水"/>
<property name="monsterId" value="666"/>
bean>
set>
property>
<property name="monsterName">
<array>
<value>小妖怪value>
<value>大妖怪value>
<value>老妖怪value>
array>
property>
<property name="pros">
<props>
<prop key="username">rootprop>
<prop key="password">123456prop>
<prop key="ip">127.0.0.1prop>
props>
property>
bean>
主要掌握 List/Map/Properties 三种集合的使用.
Properties 集合的特点
1)这个 Properties 是 Hashtable 的子类 , 是 key-value 的形式
2)key 是 string 而 value 也是 string
xmlns:util="http://www.springframework.org/schema/util"
beans.xml
<util:list id="bookList">
<value>三国演义value>
<value>被讨厌的勇气value>
<value>西游记value>
<value>三字经value>
util:list>
<bean class="com.llp.spring.bean.BookStore" id="bookStore">
<property name="bookList" ref="bookList"/>
bean>
BookStore.java
public class BookStore {
private List<String> bookList;
public List<String> getBookList() {
return bookList;
}
public void setBookList(List<String> bookList) {
this.bookList = bookList;
}
@Override
public String toString() {
return "BookStore{" +
"bookList=" + bookList +
'}';
}
}
测试
@Test
public void getBeanByUtilList(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
BookStore bean = ioc.getBean("bookStore",BookStore.class);
System.out.println(bean);
}
<bean class="com.llp.spring.bean.Emp" id="emp">
<property name="name" value="小红"/>
<property name="dept" ref="dept"/>
<property name="dept.name" value="后勤"/>
bean>
<bean class="com.llp.spring.bean.Dept" id="dept"/>
/**
* 级联属性赋值
*/
@Test
public void getBeanByRelation(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Emp bean = ioc.getBean("emp", Emp.class);
System.out.println(bean);
}
<bean id="my_monster01" class="com.llp.spring.factory.MyStaticFactory" factory-method="getBean">
<constructor-arg value="monster02"/>
bean>
MyStaticFactory工厂类
/**
* 可以创建返回Monster对象
*/
public class MyStaticFactory {
private static Map<String, Monster> monsterMap;
//使用static 代码块进行初始化
static{
monsterMap = new HashMap<>();
monsterMap.put("monster01",new Monster(100,"阿牛","芭蕉扇"));
monsterMap.put("monster02",new Monster(200,"狐狸精","美人计"));
}
//提供一个方法返回monster对象
public static Monster getBean(String key){
return monsterMap.get(key);
}
}
测试类
@Test
public void getBeanByStaticFactory(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean = ioc.getBean("my_monster01", Monster.class);
System.out.println(bean);
}
测试结果
beans.xml
<bean class="com.llp.spring.factory.MyInstanceFactory" id="instanceFactory"/>
<bean id="my_monster02" factory-bean="instanceFactory" factory-method="getMonster">
<constructor-arg value="monster03"/>
bean>
实例工厂类
public class MyInstanceFactory {
private static Map<String, Monster> monster_Map;
{
monster_Map = new HashMap<>();
monster_Map.put("monster03",new Monster(300,"孙悟空","耍光棍"));
monster_Map.put("monster04",new Monster(400,"蜘蛛精","盘丝"));
}
public Monster getMonster(String key){
return monster_Map.get(key);
}
}
测试类
@Test
public void getBeanByInstanceFactory(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster bean01 = ioc.getBean("my_monster02", Monster.class);
Monster bean02 = ioc.getBean("my_monster02", Monster.class);
System.out.println(bean01);
/**
* 这里调用my_monster02 都是调用已经创建好的MyInstanceFactory对象的getMonster方法
* 注意的是,MyInstanceFactory是单独配置的并不会创建两次
*/
System.out.println(bean01 == bean02);//true
}
测试结果
FactoryBean
/**
* 一个FactoryBean
*/
public class MyFactoryBean implements FactoryBean<Monster> {
//这个就是你配置时候,指定要获取的对象对应key
private String key;
private Map<String, Monster> monster_map;
{ //代码块,完成初始化
monster_map = new HashMap<>();
monster_map.put("monster03", new Monster(300, "牛魔王~", "芭蕉扇~"));
monster_map.put("monster04", new Monster(400, "狐狸精~", "美人计~"));
}
public void setKey(String key) {
this.key = key;
}
@Override
public Monster getObject() throws Exception {
return monster_map.get(key);
}
@Override
public Class<?> getObjectType() {
return Monster.class;
}
@Override
public boolean isSingleton() {//这里指定是否返是单例
return true;
}
}
beans.xml
<bean id="my_monster03" class="com.llp.spring.factory.MyFactoryBean">
<property name="key" value="monster04"/>
bean>
测试类
@Test
public void getBeanByFactoryBean(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster my_monster03 = ioc.getBean("my_monster03", Monster.class);
System.out.println(my_monster03);
}
测试结果
beans.xml
<bean id="monster10" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/>bean>
<bean id="monster11" class="com.llp.spring.bean.Monster" parent="monster10"/>
测试类
/**
* 配置bean通过继承(extends)
*/
@Test
public void getBeanByExtends(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster10 = ioc.getBean("monster10", Monster.class);
Monster monster11 = ioc.getBean("monster11", Monster.class);
System.out.println(monster10);
System.out.println(monster11);
//monster11对象的属性值继承至monster10,但monster11和monster10并不是同一个对象
System.out.println(monster10 == monster11);//false
}
测试结果
注意
<bean id="monster12" class="com.llp.spring.bean.Monster" abstract="true">
<property name="monsterId" value="10"/>
<property name="name" value="蜈蚣精"/>
<property name="skill" value="蜇人"/>
bean>
beans.xml
<bean id="student01" class="com.llp.spring.bean.Student" depends-on="department01"/>
<bean id="department01" class="com.llp.spring.bean.Department"/>
测试类
@Test
public void getBeanByCreate(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Student student = ioc.getBean("student01", Student.class);
Department department = ioc.getBean("department01", Department.class);
}
测试结果
● 问题说明
1)先创建 id=memberDAOImpl
2)再创建 id = memberServiceImpl
3)调用 memberServiceImpl.setMemberDAO() 完成引用
1)先创建 id = memberServiceImpl
2)再创建 id=memberDAOImpl
3)用 memberServiceImpl.setMemberDAO() 完成引用
在 spring 的 ioc 容器, 在默认是按照单例创建的,即配置一个 bean 对象后,ioc 容器只会创建一个 bean 实例。
如果,我们希望 ioc 容器配置的某个 bean 对象,是以多个实例形式创建的则可以通过配置scope=“prototype” 来指定
Cat.java
public class Cat {
private Integer id;
private String name;
public Cat() {
System.out.println("Cat() 被执行...");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//@Override
//public String toString() {
// return "Cat{" +
// "id=" + id +
// ", name='" + name + '\'' +
// '}';
//}
}
beans.xml
<bean id="cat" class="com.llp.spring.bean.Cat" scope="prototype" lazy-init="false">
<property name="id" value="100"/>
<property name="name" value="小花猫"/>
bean>
测试
@Test
public void getBeanByPrototype(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Cat cat01 = ioc.getBean("cat", Cat.class);
Cat cat02 = ioc.getBean("cat", Cat.class);
System.out.println(cat01);
System.out.println(cat02);
//false
System.out.println(cat01==cat02);
}
测试结果
默认是单例singleton, 在启动容器时, 默认就会创建 , 并放入到singletonObjects集合
当 < bean scope=“prototype” > 设置为多实例机制后, 该 bean 是在 getBean()时才创建
如 果 是 单 例 singleton, 同 时 希 望 在 getBean 时 才 创 建 , 可 以 指 定 懒 加 载 lazy-init=“true” (注意默认是 false)
通常情况下, lazy-init 就使用默认值 false , 在开发看来, 用空间换时间是值得的, 除非有特殊的要求.
如果 scope=“prototype” 这时你的 lazy-init 属性的值不管是 ture, 还是 false 都是在getBean 时候才创建对象.
● 说明: bean 对象创建是由 JVM 完成的,然后执行如下方法
House.java
public class House {
private String name;
public House() {
System.out.println("House() 构造器...");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("House setName()=" + name);
this.name = name;
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
public void init() {
System.out.println("House init()..");
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
//3. 名字也不是固定的
public void destroy() {
System.out.println("House destroy()..");
}
@Override
public String toString() {
return "House{" +
"name='" + name + '\'' +
'}';
}
}
beans.xml
<bean id="house" class="com.llp.spring.bean.House" init-method="init" destroy-method="destroy" >
<property name="name" value="北京豪宅"/>
bean>
测试
//测试Bean的生命周期
@Test
public void testBeanLife() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
House house = ioc.getBean("house", House.class);
System.out.println("使用house=" + house);
//关闭容器
//1. ioc的编译类型 ApplicationContext , 运行类型 ClassPathXmlApplicationContext
//2. 因为ClassPathXmlApplicationContext 实现了 ConfigurableApplicationContext
//3. ClassPathXmlApplicationContext 是有close
//4. 将ioc 转成ClassPathXmlApplicationContext,再调用close
//ioc.close();
//关闭ioc容器.
((ConfigurableApplicationContext) ioc).close();
}
初始化 init 方法和 destory 方法, 是程序员来指定
销毁方法就是当关闭容器时,才会被调用.
● 说明
● 应用实例演示
bean—House
public class House {
private String name;
public House() {
System.out.println("House() 构造器...");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("House setName()=" + name);
this.name = name;
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
public void init() {
System.out.println("House init()..");
}
//1. 这个方法是程序员来编写的.
//2. 根据自己的业务逻辑来写.
//3. 名字也不是固定的
public void destroy() {
System.out.println("House destroy()..");
}
@Override
public String toString() {
return "House{" +
"name='" + name + '\'' +
'}';
}
}
beans2.xml
<bean class="com.llp.spring.bean.House" id="house" init-method="init" destroy-method="destroy">
<property name="name" value="我的房子"/>
bean>
<bean class="com.llp.spring.bean.MyBeanPostProcessor"/>
后置处理器
/**
* 后置处理器
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 什么时候被调用:在Bean的init方法前被调用
* @param bean 传入的在ioc容器中创建/配置的bean
* @param beanName 传入的ioc容器中创建/配置bean的id
* @return Object 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization(),bean="+bean+",beanName="+beanName);
return bean;
}
/**
* 什么时候被调用:在Bean的init方法后被调用
* @param bean 传入的在ioc容器中创建/配置的bean
* @param beanName 传入的ioc容器中创建/配置bean的id
* @return 程序员对传入的bean 进行修改/处理【如果有需要的话】 ,返回
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization(),bean="+bean+",beanName="+beanName);
return bean;
}
}
@Test
public void testBeanPostProcessor(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");
House house = ioc.getBean("house", House.class);
System.out.println(house);
}
1、怎么执行到这个方法?=> 使用 AOP(反射+动态代理+IO+容器+注解)
2、有什么用?=> 可以对 IOC 容器中所有的对象进行统一处理 ,比如 日志处理/权限的校验
-初步体验案例: 如果类型是 House 的统一改成 上海豪宅
3、针对容器的所有对象吗? 是的=>切面编程特点
beans02.xml
<!--指定属性文件
location 表示指定属性文件的位置-->
<context:property-placeholder location="classpath:my.properties"/>
<!--配置Monster对象
1.通过属性文件给monster对象的属性赋值
2.这是我们的属性值通过${属性名}
3.这里说的属性名就是my.properties文件中的k=v的k-->
<bean class="com.llp.spring.bean.Monster" id="monster1000">
<property name="monsterId" value="${monsterId}"/>
<property name="name" value="${name}"/>
<property name="skill" value="${skill}"/>
</bean>
测试
@Test
public void setBeanByFile(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml");
Monster monster1000 = ioc.getBean("monster1000", Monster.class);
//Monster{monsterId=100, name='琪琪', skill='魅惑'}
System.out.println(monster1000);
}
public class OrderDao {
public void saveOrder(){
System.out.println("保存 一个订单...");
}
}
public class OrderServiceImpl {
private OrderDao orderDao;
public OrderDao getOrderDao() {
return orderDao;
}
public void setOrderDao(OrderDao orderDao) {
this.orderDao = orderDao;
}
public void saveOrder(){
orderDao.saveOrder();
}
}
public class OrderAction {
private OrderServiceImpl orderService;
public OrderServiceImpl getOrderService() {
return orderService;
}
public void setOrderService(OrderServiceImpl orderService) {
this.orderService = orderService;
}
public void saveOrder(){
orderService.saveOrder();
}
}
<bean class="com.llp.spring.dao.OrderDao" id="orderDao"/>
<bean class="com.llp.spring.service.OrderServiceImpl" id="orderService" autowire="byType"/>
<bean class="com.llp.spring.web.OrderAction" id="orderAction" autowire="byType"/>
<bean class="com.llp.spring.dao.OrderDao" id="orderDao"/>
<bean class="com.llp.spring.service.OrderServiceImpl" id="orderService" autowire="byName"/>
<bean class="com.llp.spring.web.OrderAction" id="orderAction" autowire="byName"/>
@Test
public void testAutowaireByName(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");
OrderAction orderAction = ioc.getBean("orderAction", OrderAction.class);
System.out.println(orderAction.getOrderService());
System.out.println(orderAction.getOrderService().getOrderDao());
}
● 说明
Spring Expression Language,Spring 表达式语言,简称 SpEL。支持运行时查询并可以操作对象。
和 EL 表达式一样,SpEL 根据 JavaBean 风格的 getXxx()、setXxx()方法定义的属性访问对象
SpEL 使用#{…}作为定界符,所有在大框号中的字符都将被认为是 SpEL 表达式。
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;
}
//cry 方法会返回字符串
public String cry(String sound) {
return "发出 " + sound + "叫声...";
}
//read 返回字符串
public static String read(String bookName) {
return "正在看 " + bookName;
}
@Override
public String toString() {
return "SpELBean{" +
"name='" + name + '\'' +
", monster=" + monster +
", monsterName='" + monsterName + '\'' +
", crySound='" + crySound + '\'' +
", bookName='" + bookName + '\'' +
", result=" + result +
'}';
}
}
<bean id="monster01" class="com.llp.spring.bean.Monster">
<property name="monsterId" value="100"/>
<property name="name" value="蜈蚣精~"/>
<property name="skill" value="蜇人~"/>
bean>
<bean id="spELBean" class="com.llp.spring.bean.SpELBean">
<property name="name" value="#{'llp'}"/>
<property name="monster" value="#{monster01}"/>
<property name="monsterName" value="#{monster01.name}"/>
<property name="crySound" value="#{spELBean.cry('喵喵的..')}"/>
<property name="bookName" value="#{T(com.llp.spring.bean.SpELBean).read('天龙八部')}"/>
<property name="result" value="#{89*1.2}"/>
bean>
//通过spring el 对属性赋值
@Test
public void setBeanBySpel() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");
SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);
System.out.println("spELBean=" + spELBean);
}
测试结果