Spring源码 - 核心接口FactoryBean

Spring源码 - 核心接口FactoryBean

Spring版本:Spring 5.3.13-release


一般情况下,Spring是通过反射机制,利用在Bean进行声明时的class属性指定的实现类来进行Bean的实例化操作。但是在某些场景下,Bean的实例化操作时非常复杂繁琐的,如果按照传统的方式,则需要在<bean></bean>中进行大量配置信息的声明,这种配置方式的灵活性会受到非常大的局限性的。而如果采用编码的方式进行声明可能会变得非常简单。org.springframework.beans.factory.FactoryBean<T>接口应运而生,用户可以实现该接口来定制实例化Bean的逻辑。

# 1、核心接口FactoryBean

FactoryBean<T>Spring占据非常重要的地位。很多第三方中间件都是通过实现FactoryBean<T>接口进行实例化。如open-feign

FactoryBean<T>接口中一共定义了三个方法:

public interface FactoryBean<T> {

	/**
	 * The name of an attribute that can be
	 * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
	 * {@link org.springframework.beans.factory.config.BeanDefinition} so that
	 * factory beans can signal their object type when it can't be deduced from
	 * the factory bean class.
	 * @since 5.2
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";


	/**
	 * Return an instance (possibly shared or independent) of the object
	 * managed by this factory.
	 * <p>As with a {@link BeanFactory}, this allows support for both the
	 * Singleton and Prototype design pattern.
	 * <p>If this FactoryBean is not fully initialized yet at the time of
	 * the call (for example because it is involved in a circular reference),
	 * throw a corresponding {@link FactoryBeanNotInitializedException}.
	 * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
	 * objects. The factory will consider this as normal value to be used; it
	 * will not throw a FactoryBeanNotInitializedException in this case anymore.
	 * FactoryBean implementations are encouraged to throw
	 * FactoryBeanNotInitializedException themselves now, as appropriate.
	 * @return an instance of the bean (can be {@code null})
	 * @throws Exception in case of creation errors
	 * @see FactoryBeanNotInitializedException
	 * @see FactoryBean#isSingleton()
	 * @see org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#singletonObjects
	 */
	@Nullable
	T getObject() throws Exception;

	/**
	 * Return the type of object that this FactoryBean creates,
	 * or {@code null} if not known in advance.
	 * <p>This allows one to check for specific types of beans without
	 * instantiating objects, for example on autowiring.
	 * <p>In the case of implementations that are creating a singleton object,
	 * this method should try to avoid singleton creation as far as possible;
	 * it should rather estimate the type in advance.
	 * For prototypes, returning a meaningful type here is advisable too.
	 * <p>This method can be called <i>before</i> this FactoryBean has
	 * been fully initialized. It must not rely on state created during
	 * initialization; of course, it can still use such state if available.
	 * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
	 * {@code null} here. Therefore it is highly recommended to implement
	 * this method properly, using the current state of the FactoryBean.
	 * @return the type of object that this FactoryBean creates,
	 * or {@code null} if not known at the time of the call
	 * @see ListableBeanFactory#getBeansOfType
	 */
	@Nullable
	Class<?> getObjectType();

	/**
	 * Is the object managed by this factory a singleton? That is,
	 * will {@link #getObject()} always return the same object
	 * (a reference that can be cached)?
	 * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
	 * the object returned from {@code getObject()} might get cached
	 * by the owning BeanFactory. Hence, do not return {@code true}
	 * unless the FactoryBean always exposes the same reference.
	 * <p>The singleton status of the FactoryBean itself will generally
	 * be provided by the owning BeanFactory; usually, it has to be
	 * defined as singleton there.
	 * <p><b>NOTE:</b> This method returning {@code false} does not
	 * necessarily indicate that returned objects are independent instances.
	 * An implementation of the extended {@link SmartFactoryBean} interface
	 * may explicitly indicate independent instances through its
	 * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
	 * implementations which do not implement this extended interface are
	 * simply assumed to always return independent instances if the
	 * {@code isSingleton()} implementation returns {@code false}.
	 * <p>The default implementation returns {@code true}, since a
	 * {@code FactoryBean} typically manages a singleton instance.
	 * @return whether the exposed object is a singleton
	 * @see #getObject()
	 * @see SmartFactoryBean#isPrototype()
	 *
	 * 返回由 FactoryBean 创建的 Bean 实例的作用域是单例还是原型
	 * true -> singleton / false -> prototype
	 */
	default boolean isSingleton() {
		return true;
	}

}
  • getObject():返回由FactoryBean创建的Bean实例,如果isSingleton()返回true,则该Bean实例会放入Spring的一级缓存中。
  • getObjectType():返回FactoryBean创建的Bean类型。
  • isSingleton():返回由FactoryBean创建的Bean实例的作用域是单例还是原型。

当声明Bean时指定的class属性为FactoryBean<T>接口的实现类时,Spring容器通过getBean()方法获取的Bean实例为T,即为getObject()方法返回的实例对象。也就是说此时FactoryBean<T>#getObject()方法代理了getBean()方法。如果需要获取此FactoryBean<T>实例,则需要通过&+BeanName进行获取。

# 2、BeanFactoryFactoryBean<T>

需要注意的是,BeanFactoryFactoryBean<T>是两个完全不同概念的接口。BeanFactory根据命名可以看出,它是一个工厂。而FactoryBean<T>根据命名也可以很清晰的看出,它是一个BeanBeanFactorySpring对于IOC思想实现的最基本方式,它提供了对Bean的管理。而FactoryBean<T>Spring针对复杂类型Bean的实例化,允许开发者对此类型的Bean进行的高级定制处理。

GitHub源码地址https://github.com/kapbc/kapcb-spring-source/tree/master/Spring-Framework-v5.3.13

备注:此文为笔者学习Spring源码的笔记,鉴于本人技术有限,文中难免出现一些错误,感谢大家批评指正。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,作为AI语言模型,我不能提供完整的代码,但是我可以为你提供一个简单的示例来展示如何将Spring Boot与Spring Security,MyBatis和MySQL集成。 首先,要使用Spring Boot,您需要在pom.xml文件中添加以下依赖项: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> </dependencies> ``` 接下来,您需要配置Spring Security,这是一个示例配置: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .antMatchers("/**").permitAll() .and() .formLogin(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 这里,我们配置了三种角色:ADMIN,USER和未经身份验证的用户,以及它们可以访问的URL。我们还配置了一个用户详细信息服务,并告诉Spring Security使用BCryptPasswordEncoder来加密密码。 接下来,我们需要设置MyBatis,这是一个示例配置: ```java @Configuration @MapperScan("com.example.demo.mapper") public class MyBatisConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource()); return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate() throws Exception { return new SqlSessionTemplate(sqlSessionFactory()); } } ``` 在这里,我们为MyBatis设置了数据,并使用@MapperScan扫描了我们的Mapper接口。 最后,我们需要编写一些代码来实现我们的应用程序逻辑。这里是一个简单的示例: ```java @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/users") public List<User> getUsers() { return userService.getUsers(); } @PostMapping("/users") public void addUser(@RequestBody User user) { userService.addUser(user); } } @Service public class UserService { @Autowired private UserMapper userMapper; public List<User> getUsers() { return userMapper.getUsers(); } public void addUser(User user) { userMapper.addUser(user); } } @Mapper public interface UserMapper { @Select("SELECT * FROM users") List<User> getUsers(); @Insert("INSERT INTO users (username, password) VALUES (#{username}, #{password})") void addUser(User user); } public class User { private Long id; private String username; private String password; // getters and setters omitted for brevity } ``` 在这里,我们定义了一个REST控制器,一个服务和一个Mapper接口,它们一起访问数据库中的用户表。我们还定义了一个User类来封装用户数据。 这只是一个简单的示例,但它应该足以帮助您开始使用Spring Boot,Spring Security,MyBatis和MySQL构建您自己的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值