1. BeanFacotry 与 FacotryBean以及FacotryBean是什么?
在spring中BeanFacotry是容器的顶层接口,定义着容器管理Bean的基础接口,我们在使用的使用一般不直接使用BeanFactory,而是使用下层的接口,诸如ApplicationContext等, 也就是我们常说的Spring的bean容器。
The FactoryBean interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.
这段官方文档也就说FactoryBean是用Spring提供给我们的扩展接口,当我们有复杂的Bean的初始化逻辑, 换言之我们bean的初始过程很复杂,并且我们又可以用代码很好的来实现bean的初始逻辑而不是用冗长的xml配置方式,那么我们就可以实现FactoryBean接口。
Tips: 本文的例子同时可以使用AOP或者使用BeanPostProcessor实现功能,只为展示FacotryBean的使用法
2. FactoryBean实战
注: 以下例子目的只为展示FactoryBean的使用方法。
现在我们有一个CarService接口, 并且有两个实现类AudiService和BmwService, 如下:
package com.example.factorybeantest.service;
public interface CarService {
void carName();
void carColor();
default void desc() {
this.carName();
this.carColor();
System.out.println("开始开车。。。。");
}
}
package com.example.factorybeantest.service;
public class AudiCarService implements CarService {
@Override
public void carName() {
System.out.println("这是一个奥迪车");
}
@Override
public void carColor() {
System.out.println("这是一个黑色的奥迪车");
}
}
package com.example.factorybeantest.service;
public class BMWCarService implements CarService {
@Override
public void carName() {
System.out.println("这是一个BMW车");
}
@Override
public void carColor() {
System.out.println("这是一个黑色的BMW车");
}
}
现在我们需要根据配置把CarServiceBean注入到Bean工厂,并且需要对该对象所有的方法进行增强。对方法的增强我们可以直接使用AOP编程,但是在这里我们直接使用动态代理实现。现在我们实现一个CarServiceFactoryBean
package com.example.factorybeantest.factory;
import com.example.factorybeantest.service.CarService;
import org.springframework.beans.factory.FactoryBean;
/**
* CAR 工厂Bean
*
* @author Elvis
* @version 1.0, 2022/11/24
*/
public class CarServiceFactoryBean implements FactoryBean<CarService> {
private CarService carService;
public CarServiceFactoryBean(CarService carService) {
this.carService = carService;
}
@Override
public CarService getObject() throws Exception {
return carService;
}
@Override
public Class<?> getObjectType() {
return carService.getClass();
}
}
然后我们添加一个配置类,把当前的FactoryBean注入到Spring容器中:
package com.example.factorybeantest.config;
import com.example.factorybeantest.factory.CarServiceFactoryBean;
import com.example.factorybeantest.proxy.CarServiceInvocationHandler;
import com.example.factorybeantest.service.CarService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Proxy;
/**
* 配置类
*/
@Configuration
@ComponentScan(basePackages = {"com.example.factorybeantest"})
public class Config {
@Value("${car.className:com.example.factorybeantest.service.AudiCarService}")
private String className;
@Bean
public CarServiceFactoryBean carService() throws Exception {
Class<?> clazz = Class.forName(className);
// 使用动态代理对Bean的方法进行增强处理
Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
new CarServiceInvocationHandler((CarService) clazz.getDeclaredConstructor().newInstance()));
return new CarServiceFactoryBean((CarService) obj);
}
}
package com.example.factorybeantest.proxy;
import com.example.factorybeantest.service.CarService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
*
*
* @author Elvis
*/
public class CarServiceInvocationHandler implements InvocationHandler {
private CarService carService;
public CarServiceInvocationHandler(CarService carService) {
this.carService = carService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("给Car加油");
Object result = method.invoke(carService, args);
System.out.println("给Car洗车");
return result;
}
}
编写测试类对FacotryBean进行测试:
package com.example.factorybeantest;
import com.example.factorybeantest.config.Config;
import com.example.factorybeantest.factory.CarServiceFactoryBean;
import com.example.factorybeantest.service.AudiCarService;
import com.example.factorybeantest.service.BMWCarService;
import com.example.factorybeantest.service.CarService;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
class FactoryBeanTestApplicationTests {
private static ApplicationContext applicationContext;
static {
applicationContext = new AnnotationConfigApplicationContext(Config.class);
}
@Test
public void testBean() {
/**
When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces,
prefix the bean’s id with the ampersand symbol (&) when calling the getBean() method of the
ApplicationContext. So, for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container
returns the product of the FactoryBean, whereas invoking getBean("&myBean") returns the FactoryBean instance itself.
*/
// 当我们需要使用工厂Bean本身的时候,需要在beanName前加上“&”
CarServiceFactoryBean factoryBean = (CarServiceFactoryBean) applicationContext.getBean("&carService");
System.out.println(factoryBean);
System.out.println("===================");
CarService carService = (CarService) applicationContext.getBean("carService");
carService.desc();
}
}
执行结果如下: