1:xml
<bean id = "" class = ""/>
2:@Bean config配置文件
3:@ComponentScan @Controller @Service @Component......
4:@import
上述四种方式,导入bean会被spring识别成BeanDefinition对象,不是单例对象
一般出现NoSuchBeanDefinitionException异常,代表该bean没有被spring管理
.class===========================>BeanDefinition对象:bean定义解析环节,然后将beanDefinition对象放到一个BeanDefinitionMap<beanName,BeanDefinition>中保存
BeanFactoryPostProcessor是用来修改beanDefinition对象的,子接口:BeanDefinitionRegistryPostProcessor的实现类来进行解析,相当于设计小组,而BeanFactoryPostProcessor的实现类来修改ben定义,相当于审核小组
BeanDefinitionRegistryPostProcessor的接口实现类有三个执行级别PriorityOrdered、Ordered、普通三个接口,优先级依次降低,优先级高的越先执行,spring帮助我们实现了优先级最高的,它的实现类是ConfigurationClassPostProcessor
BeanPostProcessor是用来修改bean定义(beanInstance)的
Bean定义===>BeanFactoryPostProcessor=====>getBean()========>BeanPostProcessor=====>单例对象
我们来看下下面案例
用Component注解修饰接口为什么会出现异常?(NoSuchBeanDefinitionException)
分析:
我们先来看前面的图解就知道问题可能会出现在@Component注解扫描这块,我们来分析ClassBeanPathDefinitionScanner(类路径bean定义扫描器)源码
再去看它的父类ClassPathScanningCandidateComponentProvider(类路径候选扫描组件提供者),看以下方法
以上代码表示不能是抽象类也不能是接口,如果我们把以上代码做出如下注释里面的修改,那这个注解就可以扫描接口了
修改后,我们继续运行下代码,发现又会出现以下错误
很明显,报错的信息就是接口不能实例化
spring底层是通过反射来实例化对象的
Class clzz=Class.forName("xxx(路径)");
因为是接口所以才会报以上的错误,路径就是bean定义的一个属性,是可以直接取到的,类似以下:
class AccountMapperDB{
beanClassName="xxxxx";
}
所以我们需要修改这个beanClassName这个属性,使他是一个代理对象的路径而不是接口的路径
想要生成代理对象,可以实现FactoryBean<?>接口,实际返回的对象就是getObject方法返回的对象,并不是carFactoryBean对象
我们来完成之前的accountMapper @Compoent注解生效
@Component(value = "accountMapper") public interface AccountMapper { String queryById(Integer id); } public class AccountFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { return Proxy.newProxyInstance(AccountMapper.class.getClassLoader(),new Class[]{AccountMapper.class},new AccountMapperProxy()); } @Override public Class<?> getObjectType() { return null; } } class AccountMapperProxy implements InvocationHandler{ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Class<?> returnType = method.getReturnType(); String o = (String) returnType.newInstance(); o="select * from test"; return o; } }@Component public class AccountMapperProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { GenericBeanDefinition accountMapper = (GenericBeanDefinition) beanFactory.getBeanDefinition("accountMapper"); accountMapper.setBeanClass(AcountMapperFactoryBean.class); } } public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AccountConfig.class); AccountMapper accountMapper = (AccountMapper) applicationContext.getBean("accountMapper"); accountMapper.queryById(11); } }
但这种方式修改上述spring源码扫描注解的地方,而且每加一个mapper都需要重写许多代码,所以会显得非常臃肿,如何优化这一点,我们在下一篇会详细说明。。。