IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 关于@Autowired的加强理解、ImportBeanDefinitionRegistrar和FactoryBean的经典应用实战 -> 正文阅读

[Java知识库]关于@Autowired的加强理解、ImportBeanDefinitionRegistrar和FactoryBean的经典应用实战

架构

?UserMapper

public interface UserMapper {

        @Select("select 'user'")
        String selectById();
    }


UserService

@Component
public class UserService {
   @Autowired
    private UserMapper userMapper;

   public void test(){
       System.out.println(userMapper.selectById());
   }
}

?主类

@ComponentScan("com.luban") //配置扫描路径 注册bean
public class LubanApplication {

    public static void main(String[] args) {
        //前三行代码启动spring
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取spring容器
        applicationContext.register(LubanApplication.class);//配置spring
        applicationContext.refresh();

        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();
    }


}

mybatis.xml?

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <environments default="development">
        <environment id="development">
            <!--使用jdbc事务管理-->
            <transactionManager type="JDBC"/>
            <!--使用连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/luban?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123123"/>
            </dataSource>
        </environment>
    </environments>



</configuration>

启动:

发现报错:

意思是spring容器中找不到UserService来进行属性注入?

当扫描到UserService上的注解@Compoent,会去实例化UserService,然后因为属性上存在注解@Autowired ,因此spring去帮我们进行属性注入,但是spring容器中并没有UserMapper类型的实例,因此报错!!!

但如果我们修改注解为@Autowired(required = false)

?再启动主类:

发现不会报刚刚的错误了,因为require=false,spring找不到就算了,而默认的true,一定要对属性赋值,因此报错

我们可以通过FactoryBean来产生一个UserMapper的代理对象,把他注入bean容器中,这样spring在近些属性注入的时候就不会报错了!!!(这个就是mybatis产生mapper对象的原理)

先创建一个User类

public class User {
}

主类中编程式声明

@ComponentScan("com.luban") //配置扫描路径 注册bean
public class LubanApplication {

    public static void main(String[] args) {
        //前三行代码启动spring
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取spring容器
        applicationContext.register(LubanApplication.class);//配置spring
            //编程式
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(LubanFactoryBean.class);
        applicationContext.registerBeanDefinition("user",beanDefinition);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("user"));

        /*UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();*/
    }


}

输出:

?

那我们直接将这里换成UserMapper吗,那可不行,spring是通过推断构造器来实现实例化的,接口可没构造器,因此你换成UserMapper会报错。?

别急,总会有方法的

新加一个类实现FactoryBean接口,这个类是个特殊的Bean

public class LubanFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        Person person = new Person();
        return person;
    }

    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }
}

修改

输出:

?再输出:

?说明一下这个特殊的Bean,若你取名为xxx,那么外面的类对应的Bean名字就是&xxx

我们可以将UserMapper的代理对象的创建在这个类中完成,这样不就可以完成属性注入了吗?

?放代码


public class LubanFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
       //mybatis UserMapper的代理对象
        Object instance = Proxy.newProxyInstance(LubanFactoryBean.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                
                System.out.println(method.getName());
                return null;
            }
        });
        return instance;
    }

    @Override
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}
ComponentScan("com.luban") //配置扫描路径 注册bean
public class LubanApplication {

    public static void main(String[] args) {
        //前三行代码启动spring
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取spring容器
        applicationContext.register(LubanApplication.class);//配置spring
            //编程式
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(LubanFactoryBean.class);
        applicationContext.registerBeanDefinition("xxx",beanDefinition);
        applicationContext.refresh();
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();
    }


}

输出:

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>

此jar里面就是我们的LubanFactoryBean类,因此可以通过注解@Autowired,直接拿来用。但是jar里的类还是和此自定义类有所不同的。我们的LubanFactoryBean是写死了UserMapper的。那jar里肯定是不能写死的

新增接口


public interface OrderMapper {
    @Select("select 'user'")
    String selectById();
}

UserService

@Component
public class UserService {
   @Autowired
    private UserMapper userMapper;
 @Autowired
    private OrderMapper orderMapper;

   public void test(){
       System.out.println(userMapper.selectById());
       System.out.println(orderMapper.selectById());
   }
}

启动报错

?那我们不可能再自定义一个LubanOrderFactoryBean(太愚蠢了)

因此我们修改LubanFactoryBean

public class LubanFactoryBean implements FactoryBean {
    private Class mapperClass;

    public LubanFactoryBean(Class mapperClass) {
        this.mapperClass = mapperClass;
    }

    @Override
    public Object getObject() throws Exception {
       //mybatis UserMapper的代理对象
        Object instance = Proxy.newProxyInstance(LubanFactoryBean.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //输出toString
                System.out.println(method.getName());
                return null;
            }
        });
        return instance;
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClass;
    }
}

主类

@ComponentScan("com.luban") //配置扫描路径 注册bean
public class LubanApplication {

    public static void main(String[] args) {
        //前三行代码启动spring
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取spring容器
        applicationContext.register(LubanApplication.class);//配置spring
            //编程式
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(LubanFactoryBean.class);  //UserMapper的代理对象
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);
        applicationContext.registerBeanDefinition("xxx",beanDefinition);

        AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(LubanFactoryBean.class);  //OrderMapper的代理对象
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);
        applicationContext.registerBeanDefinition("xxx1",beanDefinition1);


        applicationContext.refresh();
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();
    }


}

输出:

属实还是有点麻烦,不可能你多一个接口,我就要声明一个beanDefintion吧。

我们自定义一个类实现

public class LubanImportBeanDefinitionRegistarar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //编程式
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(LubanFactoryBean.class);  //UserMapper的代理对象
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);
        registry.registerBeanDefinition("xxx",beanDefinition);

        AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition1.setBeanClass(LubanFactoryBean.class);  //OrderMapper的代理对象
        beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(OrderMapper.class);
        registry.registerBeanDefinition("xxx1",beanDefinition1);

    }
}

同时简化主类

@ComponentScan("com.luban") //配置扫描路径 注册bean
@Import(LubanImportBeanDefinitionRegistarar.class)
public class LubanApplication {

    public static void main(String[] args) {
        //前三行代码启动spring
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); //获取spring容器
        applicationContext.register(LubanApplication.class);//配置spring
        applicationContext.refresh();
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.test();
    }
}

主类多了个注解@Import(LubanImportBeanDefinitionRegistarar.class),作用是去执行LubanImportBeanDefinitionRegistarar.class里的方法!!!

启动发现Ok!!!LubanImportBeanDefinitionRegistarar也是jar中的一个类

现在的问题是,LubanImportBeanDefinitionRegistarar类中的东西也是写死的!!!?、

我们应该去扫描

新建一个扫描类

public class LubanMapperScanner extends ClassPathBeanDefinitionScanner {
    public LubanMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
}

执行扫描

?

?scan等于0说明没扫描到,原因是他只会去扫描类,不会去扫描接口,因此返回0;

那我们要让他扫描接口,可以这样做

扫描类中添加此方法(修改去扫描接口而不是类)

 @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface();
    }

?同时此类新增

?再次debug

扫描类中重写方法

 @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        return beanDefinitionHolders;
    }

再次修改扫描包中的内容

 @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClassName(LubanFactoryBean.class.getName());
        }
        return beanDefinitionHolders;
    }

?删掉这个

启动输出:

修改LubanFactoryBean

public class LubanFactoryBean implements FactoryBean {
    private Class mapperClass;

    private SqlSession sqlSession;

    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
        sqlSessionFactory.getConfiguration().addMapper(mapperClass);
        this.sqlSession = sqlSessionFactory.openSession();
    }

    public LubanFactoryBean(Class mapperClass) {
        this.mapperClass = mapperClass;
    }

    @Override
    public Object getObject() throws Exception {
       //mybatis UserMapper的代理对象
        return sqlSession.getMapper(mapperClass);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClass;
    }
}

主类注册Bean

?这样也可以照常输出。mybatis的jar大致就是这样实现的

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-05 11:54:42  更:2021-12-05 11:55:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:40:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码