bean的生成
- 首先对包进行扫描,如果扫描到@component注解,根据XX.class会生成一个BeanDefinition,基于BeanDefinition中的属性通过bean工厂后置处理器进行一个修改后创建bean对象。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String var1);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String var1);
@Nullable
String getBeanClassName();
void setScope(@Nullable String var1);
@Nullable
String getScope();
void setLazyInit(boolean var1);
boolean isLazyInit();
void setDependsOn(@Nullable String... var1);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean var1);
boolean isAutowireCandidate();
void setPrimary(boolean var1);
boolean isPrimary();
void setFactoryBeanName(@Nullable String var1);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String var1);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !this.getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !this.getPropertyValues().isEmpty();
}
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
int getRole();
@Nullable
String getDescription();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
- 也可以通过@Bean生成一个对象放到spring容器中。
- FactoryBean,里面仅有一个对象,是比较小的工厂:通过实现FactoryBean接口的方法,可以获取到getObject()返回的对象
import org.springframework.beans.factory.FactoryBean;
public class myfactorybean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new A();
}
@Override
public Class<?> getObjectType() {
return A.class;
}
}
**如果是接口呢?怎么创建 **
jdk动态代理 利用了factorybean整合
public class myfactorybean implements FactoryBean {
Class mapper;
public myfactorybean(Class mapper) {
this.mapper = mapper;
}
@Override
public Object getObject() throws Exception {
//jdk 动态代理
userMapper userMapper = (userMapper) Proxy.getProxyClass(myfactorybean.class.getClassLoader(),
new Class[]{userMapper.class},
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
if(Object.class.equals(method.getDeclaringClass())){
return method.invoke(this,objects);
}
return null;
}
});
return userMapper;
}
@Override
public Class<?> getObjectType() {
return userMapper.class;
}
}
//mybatis中实际调用的invoke
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
}
若需要创建很多mapper呢?怎么利用一个facrotyBean创建?
//spring启动时执行,将生成的bd放到spring容器中
//可以通过实现 ImportBeanDefinitionRegistrar,并在registerBeanDefinitions方法中实现相关逻辑,在@Import注解,可实现自定义的bean的实现。
public class factorybeanregister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
ArrayList<Class> mappers = new ArrayList<>();//可以通过扫描获取
mappers.add(A.class);
mappers.add(userMapper.class);
for (Class mapper:mappers){
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanDefinition.setBeanClass(myfactorybean.class);//bean
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper);
registry.registerBeanDefinition(mapper.getName(),beanDefinition);
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
如何通过扫描获取mapper呢?
mybatis整合spring
可以自定义一个注解去定义扫描的dao包,并在上面加import注解去将所需要的bean加入spring容器
@Import(factorybeanregister.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface myscan {
String value() default "";
}
再在配置类中加注解@myscan("..dao"),扫描dao包。
其实在mybatis-spring jar包中有个mapperScan注解可以使用。MapperScan中Import了MapperScannerRegistrar.class;其中定义了对MapperScan中给定包路径下的类的信息进行获取-registerBeanDefinitions();
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
public static final Logger LOGGER = LoggerFactory.getLogger(MapperScannerRegistrar.class);
private ResourceLoader resourceLoader;
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// this check is needed in Spring 3.1
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
}
Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
}
Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
}
Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
//优先级 mapperHelperRef > properties > springboot
String mapperHelperRef = annoAttrs.getString("mapperHelperRef");
String[] properties = annoAttrs.getStringArray("properties");
if (StringUtils.hasText(mapperHelperRef)) {
scanner.setMapperHelperBeanName(mapperHelperRef);
} else if (properties != null && properties.length > 0) {
scanner.setMapperProperties(properties);
} else {
try {
scanner.setMapperProperties(this.environment);
} catch (Exception e) {
LOGGER.warn("只有 Spring Boot 环境中可以通过 Environment(配置文件,环境变量,运行参数等方式) 配置通用 Mapper," +
"其他环境请通过 @MapperScan 注解中的 mapperHelperRef 或 properties 参数进行配置!" +
"如果你使用 tk.mybatis.mapper.session.Configuration 配置的通用 Mapper,你可以忽略该错误!", e);
}
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
//得到bd的类型就是当前类的类型
if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
if (logger.isDebugEnabled()) {
logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName()
+ "' and '" + definition.getBeanClassName() + "' mapperInterface");
}
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); // issue #59 添加构造方法
definition.setBeanClass(this.mapperFactoryBean.getClass());
//设置通用 Mapper
if(StringUtils.hasText(this.mapperHelperBeanName)){
definition.getPropertyValues().add("mapperHelper", new RuntimeBeanReference(this.mapperHelperBeanName));
} else {
//不做任何配置的时候使用默认方式
if(this.mapperHelper == null){
this.mapperHelper = new MapperHelper();
}
definition.getPropertyValues().add("mapperHelper", this.mapperHelper);
}
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);
}
}
}