首页 > Spring整合第三方框架底层原理
头像
社交牛逼一号
发布于 2021-09-23 20:35
+ 关注

Spring整合第三方框架底层原理

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) 回帖
加载中...
话题 回帖

近期热帖

热门推荐