spring剛啓動時 會進入doGetBean方法,若是bean是首次建立,則會進入建立Bean的步驟java
先經過Factory建立對象spring
再調用getObjectForBeanInstance(sharedInstance, name, beanName, mbd)sql
getObjectForBeanInstance有三個判斷 從上至下執行bash
一般狀況下,bean 無須本身實現工廠模式,Spring 容器擔任了工廠的 角色;但少數狀況下,容器中的 bean 自己就是工廠,做用是產生其餘 bean 實例。由工廠 bean 產生的其餘 bean 實例,再也不由 Spring 容器產生,所以與普通 bean 的配置不一樣,再也不須要提供 class 元素。mybatis
先定義一個Bean實現FactoryBean接口app
@Component
public class MyBean implements FactoryBean {
private String message;
public MyBean() {
this.message = "經過構造方法初始化實例";
}
@Override
public Object getObject() throws Exception {
// 這裏並不必定要返回MyBean自身的實例,能夠是其餘任何對象的實例。
//如return new Student()...
return new MyBean("經過FactoryBean.getObject()建立實例");
}
@Override
public Class<?> getObjectType() {
return MyBean.class;
}
public String getMessage() {
return message;
}
}
複製代碼
MyBean實現了FactoryBean接口的兩個方法,getObject()是能夠返回任何對象的實例的,這裏測試就返回MyBean自身實例,且返回前給message字段賦值。同時在構造方法中也爲message賦值。而後測試代碼中先經過名稱獲取Bean實例,打印message的內容,再經過&+名稱
獲取實例並打印message內容。ide
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {
@Autowired
private ApplicationContext context;
@Test
public void test() {
MyBean myBean1 = (MyBean) context.getBean("myBean");
System.out.println("myBean1 = " + myBean1.getMessage());
MyBean myBean2 = (MyBean) context.getBean("&myBean");
System.out.println("myBean2 = " + myBean2.getMessage());
System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));
}
}
複製代碼
myBean1 = 經過FactoryBean.getObject()初始化實例
myBean2 = 經過構造方法初始化實例
myBean1.equals(myBean2) = false
複製代碼
FactoryBean在Spring中最爲典型的一個應用就是用來建立AOP的代理對象。源碼分析
首先mybatis實現MapperScannerConfigurer,用於掃描mapper文件post
由 《插手"容器的啓動"——BeanFactoryPostProcessor篇》知道,postProcessors的方法會在容器啓動某個過程當中被執行。查看BeanDefinitionRegistryPostProcessor源碼,發現繼承於BeanFactoryPostProcessor測試
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
複製代碼
BeanFactoryPostProcessor是用於在bean被初始化爲BeanDefinition
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
scanner.setAddToConfig(this.addToConfig);
scanner.setAnnotationClass(this.annotationClass);
scanner.setMarkerInterface(this.markerInterface);
scanner.setSqlSessionFactory(this.sqlSessionFactory);
scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
scanner.setResourceLoader(this.applicationContext);
scanner.setBeanNameGenerator(this.nameGenerator);
//用於配置掃描mapper的過濾器 我這裏的filter是null的 因此直接素有mapper會加載到beanDefinition中
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
複製代碼
scan
方法會走到doScan
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
//調用父類(Spring提供的ClassPathBeanDefinitionScanner進行掃描包,掃描包的類信息、註解到 BeanDefinition,最後在通過前面定義的filter,返回一個BeanDefinitionHolder),最後調用this.registerBeanDefinition(definitionHolder, this.registry)
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
for (BeanDefinitionHolder holder : beanDefinitions) {
GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// mapperInterface設爲BeanName
// MapperFactoryBean設爲BeanClass 後面會用到FactoryBean特性
definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName());
definition.setBeanClass(MapperFactoryBean.class);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
if (logger.isDebugEnabled()) {
logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
}
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
return beanDefinitions;
}
複製代碼
這裏咱們重點關注設置beanClass
設置BeanDefinition對象的BeanClass爲MapperFactoryBean<?>。這意味着什麼呢?以UserMapper爲例,意味着當前的mapper接口在Spring容器中,beanName是userMapper,beanClass是MapperFactoryBean.class。那麼在IOC初始化的時候,實例化的對象就是MapperFactoryBean對象。
如今咱們全部的**Mapper
的BeanClass
爲MapperFactoryBean<?>
,由上邊咱們知道,全部的FactoryBean在實例化時,會調用自身的getObject()方法,咱們查看下MapperFactoryBean<?>
這個類
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
private boolean addToConfig = true;
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public void setAddToConfig(boolean addToConfig) {
this.addToConfig = addToConfig;
}
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
public Class<T> getObjectType() {
return this.mapperInterface;
}
public boolean isSingleton() {
return true;
}
}
複製代碼
調用getObject會進入getMapper
利用jdk代理反射獲取對象