Spring中的bean是如何生成的
Spring提供了那些扩展点可以用来整合第三方框架?
Spring是如何整合Mybatils的?
MyBatis 框架
这里的sqlsession.getMapper是jdk动态代理得到代理对象的
return mapperProxyFactory.newInstance(sqlSession)这里得到了真正的代理对象
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.6</version> </dependency>
mybatis-spring 整合的桥梁
类---》beanDefinition---》bean
mybatis代理对象---》bean
三种方式注入bean 1 @Bean
2 后置处理器中注册一个对象 beanFactory.registerSingleton(”user“,user.class)
3 通过facatoryBean中new一个对象.
将java对象放到spring容器中它就成了一个bean
FactoryBean:
1.Bean---bean
2.特殊---getObject()
@Component public class LLFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { return new A(); } @Override public Class<?> getObjectType() { return A.class; } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println(context.getBean("LLFactoryBean")); } } com.mybatis.pojo.A@525f1e4e
返回的是a类型的对象
MyBatis代理对象的类型:
1.接口
2.类(对于的名字)
但是我们用到只有接口。
BeanFactory:Bean工厂 既包括了beanDefinition也包括了项目中的bean对象
bean的定义文件:beanDefinition 相当于描述Bena的文件
BeanFactory和FactoryBean的区别:
BeanFactory:是Spring容器中一个很大的工厂 里面存放了beanDefinition Bean对象 ....
FactoryBean:也相当于一个工厂主要负责生产一个对象。
@Component public class LLFactoryBean implements FactoryBean { //模拟MyBatis代理对象 @Override public Object getObject() throws Exception { UserMapper o = (UserMapper) Proxy.newProxyInstance(LLFactoryBean.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())){ return method.invoke(this,args); } return null; } }); return o; } @Override public Class<?> getObjectType() { return UserMapper.class; } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println(context.getBean("LLFactoryBean")); } } com.mybatis.utils.LLFactoryBean$1@52aa2946
我们使用mybatis一样的写法
if (Object.class.equals(method.getDeclaringClass())){ return method.invoke(this,args); }
这样就得到了正真的代理对象 LLFactoryBean$1也就是usermapper代理对象
如何生成指定属性的Bean
public interface UserMapper { User selectById(int id); } @Component public class UserService { @Autowired UserMapper userMapper; public User test(){ return userMapper.selectById(1); } @Component public class LLFactoryBean implements FactoryBean { //模拟MyBatis代理对象 @Override public Object getObject() throws Exception { UserMapper o = (UserMapper) Proxy.newProxyInstance(LLFactoryBean.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())){ return method.invoke(this,args); } return null; } }); return o; } @Override public Class<?> getObjectType() { return UserMapper.class; } } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println(context.getBean("userService", UserService.class)); } } com.mybatis.service.UserService@20d3d15a
我们在LLFactoryBean中描述了一个Bean UserMapper 它的类型是UserMapper 它的名字是LLFactoryBean。在我们的UserService中我们需要一个userMapper类来进行注入,这里的ByName是不行的,所以调用了ByType找到了LLFactoryBean的bean对象。所以在我们的UserService注入并调用方法的同时不会有问题。
但是当我们一个类中需要多个mapper 的时候,不可能每一个mapper都需要写一个FactoryBean。
使用Improt注解注入BeanDefinition对象,在BeanDefinition对象中进行mapper的注入。
@Component public class UserService { @Autowired UserMapper userMapper; @Autowired MyMapper myMapper; public User test(){ return userMapper.selectById(1); } public User test1(){ return myMapper.selectById(1); } } public class LLBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //逻辑 List<Class> mappers = new ArrayList<>(); mappers.add(MyMapper.class); mappers.add(UserMapper.class); for (Class mapper : mappers) { BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(); AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); beanDefinition.setBeanClass(LLFactoryBean.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper); //将beanDefinition放到spring容器中 在config配置类上面import注解进行扫描。 registry.registerBeanDefinition(mapper.getName(),beanDefinition); } } } public class LLFactoryBean implements FactoryBean { private Class mapper; public LLFactoryBean(Class mapper) { this.mapper = mapper; } //模拟MyBatis代理对象 @Override public Object getObject() throws Exception { Object o = Proxy.newProxyInstance(LLFactoryBean.class.getClassLoader(), new Class[]{mapper}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass())){ return method.invoke(this,args); } return null; } }); return o; } @Override public Class<?> getObjectType() { return mapper; } } @Configuration @ComponentScan("com.mybatis") @Import(LLBeanDefinitionRegistry.class) public class AppConfig { //配置 } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); } } com.mybatis.service.UserService@6107227e
将beanDefinition放到spring容器中 在config配置类上面import注解进行扫描。 registry.registerBeanDefinition(mapper.getName(),beanDefinition);
我们这样写也还是将mapper类写死在集合中,现在我们需要的是自动扫描出来的mapper类!
//扫描mapper注解 @Retention(RetentionPolicy.RUNTIME) @Import(LLBeanDefinitionRegistry.class) public @interface LLScan { String value() default ""; } //向spring注入 public class LLBeanDefinitionRegistry implements ImportBeanDefinitionRegistrar { //LLBeanDefinitionRegistry ---> Import @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //同过Spring拿到扫描dao层 Map<String, Object> allAnnotationAttributes = importingClassMetadata.getAnnotationAttributes(LLScan.class.getName()); //这就相当于是扫描路径 Object value = allAnnotationAttributes.get("value"); //逻辑 List<Class> mappers = new ArrayList<>(); mappers.add(MyMapper.class); mappers.add(UserMapper.class); for (Class mapper : mappers) { BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(); AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); beanDefinition.setBeanClass(LLFactoryBean.class); beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(mapper); //将beanDefinition放到spring容器中 在config配置类上面import注解进行扫描。 registry.registerBeanDefinition(mapper.getName(),beanDefinition); } } } //启动类 @Configuration @ComponentScan("com.mybatis") @LLScan("com.mybatis.dao") public class AppConfig { //配置 } public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); } } //扫描出来的dao层 com.mybatis.dao com.mybatis.service.UserService@15761df8
全部评论
(0) 回帖