FactoryBean探究
大约 2 分钟源码解析bean的注入
应用场景
一些对象的创建比较复杂,这时候就可以使用FactoryBean
,Spring容器在创建Bean的时候调用FactoryBean
实现创建。尤其是一些动态代理对象的创建。
基本使用
实现FactoryBean
接口:
public class SimpleFactoryBean implements FactoryBean<Dog> {
@Override
public Dog getObject() throws Exception {
return new Dog("大黄", 3);
}
@Override
public Class<?> getObjectType() {
return Dog.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
由于这个类没有在主启动类所在的包下,不能被默认扫描(也可以放到默认扫描的包下,使用注解把类交给Spring管理)。我们在配置类中使用@Bean
注入bean。
@SpringBootApplication
public class SpringBootAnalysisApp {
private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
Dog dog = applicationContext.getBean(Dog.class);
logger.info("dog: {}", dog);
}
@Bean
public SimpleFactoryBean simpleFactoryBean(){
return new SimpleFactoryBean();
}
}
可以看到Dog
对象的确被注入到Spring容器了。
com.sanfen.SpringBootAnalysisApp : dog: Dog{name='大黄', age=3}
进阶使用
创建FactoryBean,可以生成任意接口的动态代理对象。其实就是对mybatis的简单模拟实现。
- 指定接口。
- 通过动态代理创建对象返回。
getObjectType()
返回接口的字节码对象。
实现FactoryBean
接口:
public class MyMapperFactoryBean implements FactoryBean {
Logger logger = LoggerFactory.getLogger(MyMapperFactoryBean.class);
private final Class clazz;
public MyMapperFactoryBean(Class clazz) {
this.clazz = clazz;
}
@Override
public Object getObject() throws Exception {
return Proxy.newProxyInstance(MyMapperFactoryBean.class.getClassLoader(),
new Class[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("select".equals(method.getName())){
logger.info("[{}]的动态代理对象的select被执行了", clazz.getName());
}
if("update".equals(method.getName())){
logger.info("[{}]的动态代理对象的update被执行了", clazz.getName());
}
return null;
}
}
);
}
@Override
public Class<?> getObjectType() {
return clazz;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
把FactoryBean
实现类注入Spring容器中,并传入一个mapper接口:
@SpringBootApplication
public class SpringBootAnalysisApp {
private static final Logger logger = LoggerFactory.getLogger(SpringBootAnalysisApp.class);
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(SpringBootAnalysisApp.class, args);
UserMapper userMapper = applicationContext.getBean(UserMapper.class);
userMapper.select();
}
@Bean
MyMapperFactoryBean myMapperFactoryBean(){
return new MyMapperFactoryBean(UserMapper.class);
}
}
结果:
com.registrar.MyMapperFactoryBean : [com.registrar.UserMapper]的动态代理对象的select被执行了