1、第一个案例
1.1、Book.java
package com.atguigu.ioc; import lombok.Data; @Data public class Book { private String bid; private String bname; }
1.2、Book2.java
package com.atguigu.ioc; import lombok.Data; @Data public class Book2 extends Book { private String coffee; @Override public String toString() { return "Book2{" +super.toString()+ "coffee='" + coffee + '\'' + '}'; } }
1.3、applicationContext.html
<?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="p01" class="com.atguigu.ioc.Person"></bean> <!--下面这个b01,IOC容器管理的是Book的实例对象,是bean的真实类型--> <bean id="bo1" class="com.atguigu.ioc.Book"> <property name="bid" value="boo1"/> <property name="bname" value="Java从入门到放弃"/> </bean> <!--现在我想要Book的加强版--> <!-- 常规情况下,IOC容器会根据class属性通过反射技术调用它的无参构造方法 现在,因为class指定的类型实现了FactoryBean机制。那么IOC容器会通过反射技术调用getObject()将返回值纳入IOC --> <bean id="b02" class="com.atguigu.ioc.BookFactoryBean"></bean> </beans>
1.4、BookFactoryBean.java
package com.atguigu.ioc; import org.springframework.beans.factory.FactoryBean; public class BookFactoryBean implements FactoryBean<Book> { @Override public Book getObject() throws Exception { Book2 book2 = new Book2(); book2.setBid("b002"); book2.setBname("钢铁是怎么炼成的"); book2.setCoffee("酱香拿铁"); return book2; } @Override public Class<?> getObjectType() { return Book.class; } }
1.5、Test
@Test public void test11() { BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println(beanFactory.getBean("b02")); //Book2{Book(bid=b002, bname=钢铁是怎么炼成的)coffee='酱香拿铁'} }
Spring-IOC(Inversion of Control,控制反转)是Spring框架的核心功能之一,它通过将对象的创建和依赖关系管理交给容器来实现松耦合的设计。而Spring中IOC容器提供的FactoryBean机制则是一种创建和管理Bean的途径。它允许开发者在获取Bean时,先获取一个特定的工厂Bean,然后再由工厂Bean来生成需要的最终Bean对象。
使用FactoryBean机制,主要有以下几个步骤:
1.编写自定义的FactoryBean实现类,该实现类需要实现Spring提供的 FactoryBean接口 ,重写其中的getObject()方法和getObjectType()方法。
2.在Spring容器的配置文件中,将自定义的 FactoryBean 注册 到容器中。
3.在需要使用Bean对象的地方,通过容器获取自定义的FactoryBean对象。
4.通过调用自定义FactoryBean的getObject()方法,返回需要的Bean对象。
举个例子,假设我们有一个自定义的DataSourceFactoryBean,用于创建数据源DataSource对象。那么,在Spring的配置文件中,我们可以这样配置:
<bean id="dataSource" class="com.example.DataSourceFactoryBean"/>
在程序中,如果我们需要获取DataSource对象,可以这样:
DataSourceFactoryBean dataSourceFactoryBean = (DataSourceFactoryBean) applicationContext.getBean("dataSource"); DataSource dataSource = dataSourceFactoryBean.getObject();
FactoryBean机制在一些场景中非常有用,例如:
1.在创建Bean时需要进行一些定制化操作,比如为Bean对象设置默认属性、开启/关闭某些特性等。
2.当需要实现延迟加载、缓存等特殊需求时,FactoryBean机制可以更好地实现。
总之,FactoryBean机制是Spring框架中一个非常重要的组成部分,它提供了一种更加灵活的Bean管理方式,适用于各种不同的场景。
+---------------------------------------------------------------------+ | Client | +---------------------------------------------------------------------+ | | | 通知IOC容器加载配置文件 | |---------------------| | | +---------------------------------------------------------------------+ | IOC容器 | +---------------------------------------------------------------------+ | | | 创建FactoryBean实例 | |---------------------| | | | 将FactoryBean实例注册到IOC容器中 | |---------------------| | | +---------------------------------------------------------------------+ | FactoryBean | +---------------------------------------------------------------------+ | | | 从配置文件中获取Bean定义 | |---------------------| | | | 创建Bean实例 | |---------------------| | | | 返回Bean实例 | |---------------------| | | +---------------------------------------------------------------------+ | Client | +---------------------------------------------------------------------+ | | | 获取FactoryBean实例 | |---------------------| | | | 调用FactoryBean.getObject()方法获取Bean实例 | |---------------------| | | | 使用Bean实例 | |---------------------| | |
在这个流程中,客户端通过IOC容器获取自定义的FactoryBean实例,然后调用其getObject()方法获取最终的Bean实例。而在IOC容器中,FactoryBean实例和最终的Bean实例都被注册到容器中,由容器统一管理和维护,使得整个过程变得更加灵活和便于扩展。
2、第二个案例
2.1、ApplicationContext.xml
<?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标签中class属性指定的是HappyFactoryBean,但是将来从这里获取的bean是HappyMachine对象--> <bean id="happyMachine" class="com.atguigu.ioc.HappyFactoryBean"> <!--property标签仍然可以通过setXxx()方法给属性赋值--> <property name="machineName" value="iceCreamMachine"/> </bean> </beans>
2.2、HappyFactoryBean.java
package com.atguigu.ioc; import org.springframework.beans.factory.FactoryBean; //实现FactoryBean接口时需要指定泛型 //泛型类型就是当前工厂要生产的对象的类型 public class HappyFactoryBean implements FactoryBean<HappyMachine> { private String machineName; public String getMachineName() { return machineName; } public void setMachineName(String machineName) { this.machineName = machineName; } @Override public HappyMachine getObject() throws Exception { //方法内部模拟创建、设置一个对象的复杂过程 HappyMachine happyMachine = new HappyMachine(); happyMachine.setMachineName(this.machineName); return happyMachine; } @Override public Class<?> getObjectType() { //返回要生产的对象的类型 return HappyMachine.class; } } class HappyMachine { private String machineName; public String getMachineName() { return machineName; } public void setMachineName(String machineName) { this.machineName = machineName; } }
2.3、Test
@Test public void testExperiment() { ApplicationContext iocContainer = new ClassPathXmlApplicationContext("applicationContext.xml"); //注意:直接根据声明FactoryBean的id,获取的是getObject方法返回的对象 HappyMachine happyMachine = iocContainer.getBean("happyMachine", HappyMachine.class); System.out.println("happyMachine = " + happyMachine); //如果想要获取FactoryBean对象,直接在id前添加&符号即可! 这是一种固定的约束 Object bean = iocContainer.getBean("&happyMachine"); System.out.println("bean = " + bean); } //happyMachine = com.atguigu.ioc.HappyMachine@4d02f94e //bean = com.atguigu.ioc.HappyFactoryBean@2b48a640