欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > Spring |(二)IoC相关内容 | bean

Spring |(二)IoC相关内容 | bean

2024/11/30 13:14:29 来源:https://blog.csdn.net/m0_63398413/article/details/143954423  浏览:    关键词:Spring |(二)IoC相关内容 | bean

文章目录

  • 📚bean基础配置
    • 🐇bean的id和class
    • 🐇bean的name属性
    • 🐇bean作用范围scope配置
    • 🐇bean基础配置小结
  • 📚bean实例化
    • 🐇构造方法实例化(常用)
    • 🐇静态工厂实例化
    • 🐇实例工厂与FactoryBean
  • 📚bean的生命周期
    • 🐇生命周期设置
    • 🐇销毁操作未调用解决方法
    • 🐇Spring提供的生命周期控制接口

学习来源:黑马程序员SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术

📚bean基础配置

🐇bean的id和class

  • id:使用容器可以通过id值获取对应的bean,在一个容器中id值唯一
  • class:bean的类型,即配置的bean的全路径类名
    在这里插入图片描述

🐇bean的name属性

  • name属性,定义bean的别名,可定义多个,使用逗号、分号、空格分隔。
    在这里插入图片描述

  • 配置别名:打开spring的配置文件applicationContext.xml。

    <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔-->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl"><property name="bookDao" ref="bookDao"/>
    </bean>
    
  • 根据名称容器获取bean对象(对应名称必须在spring配置文件中存在)

    public class AppForName {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象BookService bookService = (BookService) ctx.getBean("service4");bookService.save();}
    }
    

🐇bean作用范围scope配置

  • 验证思路:同一个bean获取两次,将对象打印到控制台,看打印出的地址值是否一致。

    BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
    BookDao bookDao2 = (BookDao) ctx.getBean("bookDao");
    System.out.println(bookDao1);
    System.out.println(bookDao2);
    

    打印结果:
    在这里插入图片描述

  • 默认情况下,Spring创建的bean对象都是单例的。

  • 在Spring配置文件中,配置scope属性来实现bean的非单例创建。

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope=""/>
    
    • 将scope设置为singleton
      在这里插入图片描述
    • 将scope设置为prototype
      在这里插入图片描述
  • bean默认为单例? bean为单例是指在Spring的IoC容器中只会有该类的一个对象。这避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高。

  • 线程安全问题?

    • 如果对象是有状态对象,即该对象有成员变量可以用来存储数据,那所有请求线程共用一个bean对象会存在线程安全问题。
    • 如果对象是无状态对象,即该对象没有成员变量进行数据存储的,方法中的局部变量在方法调用完成后会被销毁,不会存在线程安全问题。
  • 表现层对象、业务层对象、数据层对象、工具对象适合交给容器进行管理。

  • 封装实例的域对象,因为会引发线程安全问题,不适合交给容器进行管理。

🐇bean基础配置小结

在这里插入图片描述

📚bean实例化

以下涉及到的project结构如下:
在这里插入图片描述

🐇构造方法实例化(常用)

  • bean本质上就是对象,对象在new的时候会使用构造方法完成,创建bean也是使用构造方法完成的。
  • 步骤1:准备一个BookDao和BookDaoImpl类,即【提供可访问的构造方法】。
    public interface BookDao {public void save();
    }public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}}
    
  • 步骤2:将类【配置】到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/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--方式一--><bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/></beans>
    
  • 步骤3:编写运行程序
    public class AppForInstanceBook {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
    }
    
  • Spring容器在创建对象的时候走的是类的无参构造方法,且底层用的是反射,能访问类中的私有构造方法。真正在使用这种方式的时候,我们什么也不需要做。

🐇静态工厂实例化

  • 步骤1:准备一个OrderDao和OrderDaoImpl类。
    public interface OrderDao {public void save();
    }public class OrderDaoImpl implements OrderDao {public void save() {System.out.println("order dao save ...");}
    }
    
  • 步骤2:创建一个工厂类OrderDaoFactory并提供一个【静态方法】。
    //静态工厂创建对象
    public class OrderDaoFactory {public static OrderDao getOrderDao(){return new OrderDaoImpl();}
    }
    
  • 步骤3:在spring的【配置】文件application.properties中添加以下内容↓
    <!--方式二-->
    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
    
    在这里插入图片描述
  • 步骤4:在AppForInstanceOrder运行类,使用从IoC容器中获取bean的方法进行运行测试
    public class AppForInstanceOrder {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");orderDao.save();}
    }
    

  • 静态工厂方法的意义?
    • 主要的原因是在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少(直接new对象的方式就无法添加其他的业务内容),比如:
      public class OrderDaoFactory {public static OrderDao getOrderDao(){System.out.println("factory setup....");//模拟必要的业务操作return new OrderDaoImpl();}
      }
      
  • 静态工厂实例化一般是用来兼容早期的一些老系统,所以了解为主

🐇实例工厂与FactoryBean

  • 步骤1:准备一个UserDao和UserDaoImpl类。
    public interface UserDao {public void save();
    }public class UserDaoImpl implements UserDao {public void save() {System.out.println("user dao save ...");}
    }
    
  • 步骤2:创建一个【实例工厂】类OrderDaoFactory并提供一个普通方法(注意此处和静态工厂的工厂类不一样的是不是静态方法)。
    public class UserDaoFactory {public UserDao getUserDao(){return new UserDaoImpl();}
    }
    
  • 步骤3:在spring的【配置】文件中添加以下内容↓
    <!--方式三-->
    <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
    
    在这里插入图片描述
  • 步骤4:在AppForInstanceUser运行类,使用从IoC容器中获取bean的方法进行运行测试。
    public class AppForInstanceUser {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");UserDao userDao = (UserDao) ctx.getBean("userDao");userDao.save();}
    }
    

  • 以上就是实例工厂实例化的方式,Spring为了简化这种配置方式提供了一种叫FactoryBean的方式来简化开发。
    在这里插入图片描述

  • 步骤1:【创建一个UserDaoFactoryBean的类】,【实现FactoryBean接口】,重写接口的方法。

    public class UserDaoFactoryBean implements FactoryBean<UserDao> {//【代替】原始实例工厂中创建对象的方法public UserDao getObject() throws Exception {return new UserDaoImpl();}//返回所创建类的Class对象public Class<?> getObjectType() {return UserDao.class;}
    }
    
    • 这里造出的对象【默认是单例】的,如果要改成非单例,则加上下
      public boolean isSingleton() {return false;
      }
      
  • 步骤2:在Spring的配置文件中进行配置。

    <!--方式四-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
    
  • 步骤3:AppForInstanceUser运行类不用做任何修改,直接运行。


在这里插入图片描述

📚bean的生命周期

⭐️下述内容涉及到的环境配置↓
在这里插入图片描述

  1. 项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类。
    public interface BookDao {public void save();
    }public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}
    }public interface BookService {public void save();
    }public class BookServiceImpl implements BookService{private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}public void save() {System.out.println("book service save ...");bookDao.save();}
    }
    
  2. resources下提供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/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    </beans>
    
  3. 编写AppForLifeCycle运行类,加载Spring的IoC容器,并从中获取对应的bean对象。
    public class AppForLifeCycle {public static void main( String[] args ) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
    }
    

🐇生命周期设置

  • 生命周期:从创建到消亡的完整过程。
  • 在上面这个环境中来为BookDao添加生命周期的控制方法,具体的控制有两个阶段:
    • bean创建之后,想要添加内容,比如用来初始化需要用到资源。
    • bean销毁之前,想要添加内容,比如用来释放用到的资源。
  • 步骤1:添加初始化和销毁方法。在BooDaoImpl类中分别添加两个方法(方法名任意)。
    public class BookDaoImpl implements BookDao {public void save() {System.out.println("book dao save ...");}//表示bean初始化对应的操作public void init(){System.out.println("init...");}//表示bean销毁前对应的操作public void destory(){System.out.println("destory...");}
    }
    
  • 步骤2:配置生命周期。
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
    
  • 步骤3:AppForLifeCycle.java运行。
    public class AppForLifeCycle {public static void main( String[] args ) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
    }
    
  • 运行AppForLifeCycle打印结果为:
    在这里插入图片描述
  • init方法执行了,但是destroy方法却未执行?
    • Spring的IoC容器是运行在JVM中。
    • 运行main方法后,JVM启动,Spring加载配置文件生成IoC容器,从容器获取bean对象,然后调方法执行。
    • main方法执行完后,JVM退出,这个时候IoC容器中的bean还没有来得及销毁就已经结束了,所以没有调用对应的destroy方法。

🐇销毁操作未调用解决方法

  • 方法一】:close()关闭容器

    public class AppForLifeCycle {public static void main( String[] args ) {//ApplicationContext中没有close方法,将ApplicationContext更换成ClassPathXmlApplicationContextClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();//关闭容器(这句话一出现就直接暴力关闭)ctx.close();}
    }
    

    在这里插入图片描述

  • 方法二】:注册钩子关闭容器,registerShutdownHook()。在容器未关闭之前,提前设置好回调函数,让JVM在退出之前回调此函数来关闭容器。

    public class AppForLifeCycle {public static void main( String[] args ) {//registerShutdownHook在ApplicationContext中也没有ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器(这句代码可以往后放,位置放哪不影响)ctx.registerShutdownHook();BookDao bookDao = (BookDao) ctx.getBean("bookDao");bookDao.save();}
    }
    

    在这里插入图片描述

  • 👀比较上述两种方法

    • 相同点:这两种都能用来关闭容器。
    • 不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。

🐇Spring提供的生命周期控制接口

  • Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-methoddestroy-method
  • 在BookServiceImpl完成这两个接口的使用:修改BookServiceImpl类,添加两个接口InitializingBeanDisposableBean并实现接口中的两个方法afterPropertiesSetdestroy
    public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {private BookDao bookDao;public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}public void save() {System.out.println("book service save ...");bookDao.save(); }public void destroy() throws Exception {System.out.println("service destroy");}public void afterPropertiesSet() throws Exception {System.out.println("service init");}
    }
    
  • 重新运行AppForLifeCycle类↓
    在这里插入图片描述

⭐️小细节

  • 对于InitializingBean接口中的afterPropertiesSet方法,翻译过来为属性设置之后,对于BookServiceImpl来说,bookDao是它的一个属性,setBookDao方法是Spring的IoC容器为其注入属性的方法。
  • 思考:afterPropertiesSet和setBookDao谁先执行?
    • 验证——在setBookDao方法中添加一句话↓
      public void setBookDao(BookDao bookDao) {System.out.println("set .....");this.bookDao = bookDao;
      }
      
    • 重新运行AppForLifeCycle,打印结果如下↓
      在这里插入图片描述
    • 所以初始化方法会在类中属性设置之后执行。

⭐️对于bean的生命周期控制在bean的整个生命周期中所处的位置如下
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com