上一节主要说了bean注册流程,下面再补充介绍其中关键的流程
再解析有@Config主机类时,也会处理@import
@Configuration
@ComponentScan("com.lmq.BaseService")
@Import("实现ImportBeanDefinitionRegistrar接口的类") //也可以是normal类,importSelect
public class AppConfig {
...........
//实现ImportBeanDefinitionRegistrar接口的类可以帮beanfactory加入某个bean对象,尤其是为接口生成动态代理对象添加到spring的bean中,比如mybatis的mapper接口
spring注册类方法:
1,register() //需要是一个类,无法参与生成bd
2, scan() //需要是一个类,或者注解,无法参与生成bd
3,ImportBeanDefinitionRegistrar, 好处参与生成bd ,好比MapperScan把@mapper接口变成对象,
@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
String[] value() default {};
其中MapperScannerRegistrar.class帮助注册一个bean,
class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
public MapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {。。。。//这里registry上节讲过是beanfactory
}
以上是例子,帮助理解ImportBeanDefinitionRegistrar
扯远了
进去此方法,
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {//import 普通类
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
顺便提下
AService{
@Autowired
Adao dao
}
对于Bservice extends Aservice
@Autowired
Adao dao 不会实例化
对于Bservice implements Aservice
@Autowired
Adao dao 会实例化
spring的自动装配
继续介绍,
@Configuration
@ComponentScan("com.lmq.BaseService")
//@Import("ImportBeanDefinitionRegistrar")
@Import(MyImportSelect.class) //相当于后面注册UserController.class,并实例化添加到spring的bean
public class AppConfig {
。。。。。。。
}
public class MyImportSelect implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{UserController.class.getName()};
}
}
但引用@Import(MyImportSelect.class) ,UserController.class是需要存在项目的,无法创建代理对象,所以需要
ImportBeanDefinitionRegistrar;
这里以uerMapper接口为例来模仿mybatis的
mapperscan,注册并添加实例对象到spring的bean中
其中UserMapper:
public interface UserMapper {
@Select("select * from user")
public List<User> findUserInfo(String name);
}
自定义MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/**
* 得到bd,或者类信息,这里对于接口类,假设实现创建代理对象,
*/
//这里先写死去为某个接口去创建动态代理对象,其实可以模拟扫描注解的接口,类似mybatis的mapperscan, UserMapper是个接口
// UserMapper userMapper= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("in proxy");
// return null;
// }
// });
// BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(userMapper.getClass()); //实际无法获取代理类信息,使用factorybean
BeanDefinitionBuilder beanDefinitionBuilder= BeanDefinitionBuilder.genericBeanDefinition(UserMapper.class);
GenericBeanDefinition beanDefinition= (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();
//为了传参数,可以给bd添加构造函数
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("com.lmq.dao.UserMapper");
beanDefinition.setBeanClass(MyFactoryBean.class); //MyFactoryBean不能加Componenrt注解
registry.registerBeanDefinition("userMapper",beanDefinition);
}
}
其中
public class MyFactoryBean implements FactoryBean {
Class clazz;
public MyFactoryBean( Class clazz)
{
this.clazz=clazz;
}
@Override
public Object getObject() throws Exception {
Class []clazz= new Class[]{this.clazz};
Object proxy= (UserMapper) Proxy.newProxyInstance(MainTest.class.getClassLoader(),clazz, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("in proxy");
//为了模仿mybatis执行sql
Method method1 =proxy.getClass().getInterfaces()[0].getMethod(method.getName(),String.class);
Select select =method1.getDeclaredAnnotation(Select.class);
System.out.println(select.value()[0]);
return null;
}
});
return proxy;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
这里AppConfig引入MyImportBeanDefinitionRegistrar.class
@Configuration
@ComponentScan("com.lmq.BaseService")
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfig {
}
AnnotationConfigApplicationContext lmqcontext = new AnnotationConfigApplicationContext(AppConfig.class);
//方式一
// LmqService lmq = lmqcontext.getBean(LmqService.class);
// LmqService lmq = lmqcontext.getBean("lmqService");
// lmq.printSys();
UserMapper lmq = (UserMapper) lmqcontext.getBean("userMapper");
lmq.findUserInfo();
输出结果:
便实现往spring添加bean对象实例了哈,生成动态代理实例,类似mybtais mapperScan扫描接口.
核心是MyFactoryBean, 类似的其实mybatis有MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface; //同样是接口参数,MyFactoryBean参考类似的,目标是为接口生成代理对象
private boolean addToConfig = true;
public MapperFactoryBean() {
}
......................
再看下MapperScannerRegistrar,也用了MapperFactoryBean
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private ResourceLoader resourceLoader;
public MapperScannerRegistrar() {
}
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.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((BeanNameGenerator)BeanUtils.instantiateClass(generatorClass));
}
Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean((MapperFactoryBean)BeanUtils.instantiateClass(mapperFactoryBeanClass));
}
scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));
List<String> basePackages = new ArrayList();
String[] var10 = annoAttrs.getStringArray("value");
int var11 = var10.length;
int var12;
String pkg;
for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
var10 = annoAttrs.getStringArray("basePackages");
var11 = var10.length;
for(var12 = 0; var12 < var11; ++var12) {
pkg = var10[var12];
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
Class[] var14 = annoAttrs.getClassArray("basePackageClasses");
var11 = var14.length;
for(var12 = 0; var12 < var11; ++var12) {
Class<?> clazz = var14[var12];
basePackages.add(ClassUtils.getPackageName(clazz));
}
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(basePackages));
}
省略