1

day05-Spring管理Bean-IOC-03 - 一刀一个小西瓜

 1 year ago
source link: https://www.cnblogs.com/liyuelian/p/17060598.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring管理Bean-IOC-03

2.基于XML配置bean

2.15bean的生命周期

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

  1. 执行构造器
  2. 执行set相关方法
  3. 调用bean的初始化方法(需要配置)
  4. 使用bean
  5. 容器关闭时,调用bean的销毁方法(需要配置)

House:

package com.li.bean; /** * @author 李 * @version 1.0 */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; } //说明:初始化方法是自定义的,名字随意,只要配置的时候指定名称就行了 public void init() { System.out.println("House init() 被执行..."); } //说明:销毁的方法是也自定义的,名字随意 public void destroy() { System.out.println("House destroy() 被执行..."); }}

beans.xml:

<!--配置House对象,演示bean的生命周期 1.init-method 指定bean的初始化方法,该方法在bean执行setter方法后执行 2.init-method指定方法执行的时机,由spring容器来控制 3.destroy-method 指定bean的销毁方法,该方法在容器关闭的时候被执行 4.destroy-method指定方法执行的时机,也是由spring容器来控制--><bean class="com.li.bean.House" id="house" init-method="init" destroy-method="destroy"> <property name="name" value="北京大豪宅"/></bean>

测试方法:

//测试bean的生命周期@Testpublic 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.而ConfigurableApplicationContext接口有 close方法 // 4.因此将ioc转成 ConfigurableApplicationContext 类型,调用close方法,关闭容器 ((ConfigurableApplicationContext)ioc).close();}
image-20230118165712355

使用细节:

  1. 初始化方法和销毁方法由程序员自定义(包括方法名称,在配置bean的时候指定即可)
  2. 销毁方法只有当关闭容器时才会被调用

2.16配置bean的后置处理器

  1. 在spring的ioc容器,可以配置bean的后置处理器(后置处理器其实就是一个java对象)
  2. 该处理器会在bean 初始化方法调用前 和 初始化方法调用后 被调用
  3. 程序员可以在后置处理器中编写自己的业务代码

1.House类(见2.15),该方法设置了构造函数,bean初始化方法等

2.创建后置处理器MyBeanPostProcessor:

后置处理器需要实现BeanPostProcessor接口,该接口中有两个重要的方法,对应我们之前说的 “初始化方法调用前和初始化方法调用后被调用”

package com.li.bean; import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor; /** * @author 李 * @version 1.0 * 这是一个后置处理器,必须实现接口 BeanPostProcessor */public class MyBeanPostProcessor implements BeanPostProcessor { /** * 调用时机:在Bean初始化方法前被调用(bean没有配置初始化方法,此方法也会被调用) * * @param bean 传入 在IOC容器中创建/配置的Bean * @param beanName 在IOC容器中创建/配置的Bean的id * @return Object 返回 bean(返回前程序员可以对bean进行修改/处理,再返回) * @throws BeansException */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization()被调用..." + "bean=" + bean + " beanName=" + beanName); return bean; } /** * 调用时机:在Bean初始化方法后被调用(bean没有配置初始化方法,此方法也会被调用) * * @param bean 传入 在IOC容器中创建/配置的Bean * @param beanName 在IOC容器中创建/配置的Bean的id * @return Object 返回 bean(返回前程序员可以对bean进行修改/处理,再返回) * @throws BeansException */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization()被调用..." + "bean=" + bean + " beanName=" + beanName); return bean; }}

3.beans02.xml:

因为后置处理器对象会作用在容器配置文件的所有bean对象中,因此这里新创建一个容器文件beans02.xml,为了输出干净,该配置文件中只配置了house一个bean对象

<!--配置House对象--><bean class="com.li.bean.House" id="house" init-method="init" destroy-method="destroy"> <property name="name" value="海景大豪宅"/></bean> <!--配置后置处理器对象 1.当我们在beans02.xml容器配置文件 配置了MyBeanPostProcessor后 2.该后置处理器对象,就会作用在该容器文件的所有Bean对象中--><bean class="com.li.bean.MyBeanPostProcessor" id="myBeanPostProcessor"/>

4.测试方法:

//测试bean的后置处理器@Testpublic void testBeanPostProcessor() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans02.xml"); House house = ioc.getBean("house", House.class); System.out.println("使用house=" + house); //关闭容器 ((ClassPathXmlApplicationContext)ioc).close();}

输出如下:postProcessBeforeInitialization()和postProcessAfterInitialization()方法分别在bean的初始化方法前后调用

image-20230118174535499

细节说明:

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

后置处理器是一个比较难理解的知识点,后面会实现这个机制,深入理解

2.17通过属性文件给bean注入值

在spring的ioc容器中,可以通过属性文件给bean注入值

1.在src目录下创建my.properties文件

monsterId=1000name=jackskill=hello

2.在beans.xml中配置:

使用配置文件的方式需要引入命名空间:

image-20230118182107473
<!--指定属性文件 1.注意要引入命名空间才能使用 2.location="classpath:my.properties" 表示指定属性文件的位置 (注意需要带上"classpath") 3.这时我们的属性值通过${属性名} 获取 4.这里的属性名就是my.properties中的 key --><context:property-placeholder location="classpath:my.properties"/> <!--配置Monster对象 通过属性文件给Monster对象赋值--><bean class="com.li.bean.Monster" id="monster1000"> <property name="monsterId" value="${monsterId}"/> <property name="name" value="${name}"/> <property name="skill" value="${skill}"/></bean>

3.测试:

//通过属性文件给bean属性赋值@Testpublic void setBeanByFile() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); Monster monster1000 = ioc.getBean("monster1000", Monster.class); System.out.println("monster1000=" + monster1000);}
image-20230118183405855

注意:如果properties文件中的value是中文,会出现乱码,需要将中文转为unicode编码:

image-20230118183938938

2.18基于XML的bean自动装配

在spring的ioc容器中,可以实现自动装配bean

1.OrderDAO

package com.li.dao; /** * @author 李 * @version 1.0 * 这是一个DAO类 */public class OrderDAO { public void saveOrder() { System.out.println("保存一个订单..."); }}

2.OrderService

package com.li.service; import com.li.dao.OrderDAO; /** * @author 李 * @version 1.0 * 这是一个Service类 */public class OrderService { //OrderDAO属性 private OrderDAO orderDAO; //getter public OrderDAO getOrderDAO() { return orderDAO; } //setter public void setOrderDAO(OrderDAO orderDAO) { this.orderDAO = orderDAO; }}

3.OrderServlet:

package com.li.web; import com.li.service.OrderService; /** * @author 李 * @version 1.0 * Servlet即 Controller */public class OrderServlet { //属性OrderService private OrderService orderService; //getter public OrderService getOrderService() { return orderService; } //setter public void setOrderService(OrderService orderService) { this.orderService = orderService; }}

4.beans.xml:

  • autowire="byType"方式
<!--配置OrderDAO对象--><bean class="com.li.dao.OrderDAO" id="orderDAO"/> <!--配置OrderService对象 1. 属性 autowire="byType" 表示在创建OrderService时, 通过类型的方式,给对象的属性自动完成赋值/引用 2. 比如OrderService对象有private OrderDAO属性,就会在容器中找有没有OrderDAO类型的对象 如果有,就会自动进行装配(按照类型的方式来装配时,那么该容器中不能有超过一个OrderService对象)--><bean autowire="byType" class="com.li.service.OrderService" id="orderService"/> <!--配置OrderServlet对象,同理--><bean autowire="byType" class="com.li.web.OrderServlet" id="orderServlet"/>
  • 使用autowire="byName"方式
<!--配置OrderDAO对象--><bean class="com.li.dao.OrderDAO" id="orderDAO"/> <!--配置OrderService对象 3.如果设置的是 autowire="byName" 表示通过名字完成自动装配 比如下面的 autowire=" byName" class="com.li.service.OrderService" (1)spring会按照 OrderService对象的属性(如orderDAO) (2)找到这个属性的setXxx()方法的Xxx名称,在容器中找到相同id的对象来进行自动装配 (3)例如我们的orderService对象中有一个setOrderDAO(),就会找id="orderDAO"的对象来进行自动装配 (4)如果没有就装配失败--><bean autowire="byName" class="com.li.service.OrderService" id="orderService"/> <!--配置OrderServlet对象,同理--><bean autowire="byName" class="com.li.web.OrderServlet" id="orderServlet"/>

注意:autowire="byName"不是通过对象属性名来找到要自动装配的对象的,而是通过setXxx方法的名称来找,因为底层是反射实现的。因此如果对象的属性的setXxx方法的名称改变了,被自动装配的对象id也要随之改变

5.测试类:

//基于XML的bean自动装配@Testpublic void setBeanByAutowire() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); OrderServlet orderServlet = ioc.getBean("orderServlet", OrderServlet.class); //验证是否自动装配上了OrderService System.out.println(orderServlet.getOrderService()); //验证是否自动装配上了OrderDAO System.out.println(orderServlet.getOrderService().getOrderDAO());}

可以看到orderServlet的orderService属性,以及属性的属性orderDAO成功装载了:(autowire="byType"/"byName"方式)

image-20230118193845625

2.19Spring EL表达式

非重点,了解即可

  1. Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象。
  2. 和 JSP的EL表达式一样,SpEL根据Javabean风格的getXxx()、setXxx()方法定义的属性访问对象
  3. SpEL使用#{}作为定界符,所有在大括号中的字符都将被认为是SpEL表达式

SpELBean:

package com.li.bean; /** * @author 李 * @version 1.0 */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 + '}'; }}

配置beans03.xml:

<!--配置一个Monster对象--><bean class="com.li.bean.Monster" id="monster01"> <property name="monsterId" value="100"/> <property name="name" value="蜈蚣精"/> <property name="skill" value="蜇人"/></bean> <!--spring el 表达式使用-通过sp el给bean的属性赋值--><bean class="com.li.bean.SpELBean" id="spELBean"> <!--sp el 给字面量--> <property name="name" value="#{'一只猫猫'}"/> <!--sp el 引用其他 bean(该bean要存在)--> <property name="monster" value="#{monster01}"/> <!--sp el 引用其他 bean 的属性值--> <property name="monsterName" value="#{monster01.name}"/> <!--sp el 调用普通方法,将该方法的返回值赋给 bean对象的属性--> <property name="crySound" value="#{spELBean.cry('喵喵喵')}"/> <!--sp el 调用静态方法,将该方法的返回值赋给 bean对象的属性 注意:需要写上类全路径--> <property name="bookName" value="#{T(com.li.bean.SpELBean).read('红楼梦')}"/> <!--sp el 通过运算赋值--> <property name="result" value="#{89*1.0+33/3}"/></bean>
//通过spring el 对属性赋值@Testpublic void setBeanBySpel() { ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml"); SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class); System.out.println(spELBean);}
image-20230118211255129
image-20230118211301603

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK