首页 > 单例Bean,单例模式,单例池之间的联系与底层原理
头像
社交牛逼一号
发布于 2021-09-23 20:18
+ 关注

单例Bean,单例模式,单例池之间的联系与底层原理

单例Bean:不是指在Spring容器中只有一个userService类型的对象,可以有多个此类型的对象。Spring找到对应的对象是先 byType 再 byName。

通过@Bean标签就可以看出来Spring中的单例Bean并不是指只有一个此类型的对象。

单例模式:单例类只能有一个实例,单例类必须自己创建自己的唯一实例,单例类必须给所有类提供这一实例。

单例池:是用来是实现单例Bean的,单例池就是一个Map Bean对象的名字就是它的键,bean对象就是值。

FactoryBean的作用和底层
public class UserService {

    @Autowired
    UserMapper userMapper;

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

对于这个userMapper它就是MyBatils框架创建的代理对象,是由MyBatils创建的代理对象赋值给这个userMapper。

Spring想要使用这个MyBatils所产生的对象,就要把他放入到Spring容器中成为一个Bean,那么他是怎么让这个对象成为这个Bean的呢?

Spring事务的实现:

1 申明式:@Transan

2 编程式:使用TransaMananger类

如何定义一个Bean;

1 申明式:@Bean @Service <bean>....

2 编程式:使用BeanDefinition

package com.test.pojo;
public class User {

}
package com.test;

import com.test.pojo.User;
import com.test.service.UserService;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.test")
public class LuoGeApplaction implements InstantiationAwareBeanPostProcessor {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LuoGeApplaction.cla***Spring
        //表示用来定义bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);
        context.refresh();
        System.out.println(context.getBean("user"));


//        UserService userService = context.getBean("userService", UserService.class);
//        userService.test();
    }
}
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'user' available
    

我们这样式得不到这个User对象的,因为我们只是扫描了这个类,但是并没有将他放到我们Spring容器中,所以我们还需要一步。

@ComponentScan("com.test")
public class LuoGeApplaction implements InstantiationAwareBeanPostProcessor {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LuoGeApplaction.cla***Spring
        //表示用来定义bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);
        //将user对象注入到这个beanDefintion中。
        context.registerBeanDefinition("user",beanDefinition);

        context.refresh();
        System.out.println(context.getBean("user"));}}

com.test.pojo.User@6dde5c8c
这就是我们的编程式得到Bean对象,那么我们的这些@Bean @Component....注解的底层肯定跟这个beanDefintion有很大的关系。也就是说式BeanDefinition实现的注解。

那么我们将User.class 换成UserService.class就可以得UserService对象嘛?

   public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LuoGeApplaction.cla***Spring

        //表示用来定义bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(UserMapper.class);
        //将user对象注入到这个beanDefintion中。
        context.registerBeanDefinition("user",beanDefinition);

        context.refresh();
        System.out.println(context.getBean("user"));
        
       org.springframework.context.support.AbstractApplicationContext refresh
答案式否定的,并不能得到UserService对象,下面我们就引出FactoryBean。



 

FactoryBean中有三个方法,你想去实现一个接口你就得实现他的方法,但是这里有默认实现,你就可以不用实现,也可以实现接口。(java8才可以,java7无法实现)

public class LuoGeBeanFactory implements FactoryBean {
    public Object getObject() throws Exception {
        return new User();
    }

    public Class<?> getObjectType() {
        return User.class;
    }
}

public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LuoGeApplaction.cla***Spring

        //表示用来定义bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //此时的LuoGeBeanFactory对应了两个对象
        beanDefinition.setBeanClass(LuoGeBeanFactory.class);
        //将user对象注入到这个beanDefintion中。
        context.registerBeanDefinition("user",beanDefinition);

        context.refresh();
        System.out.println(context.getBean("user"));
        System.out.println(context.getBean("&user"));
        
com.test.pojo.User@35a50a4c
com.mybatils.spring.LuoGeBeanFactory@1f021e6c

我们可以看到确实得到了LuoGeBeanFactory和User两个对象。那么现在我们就知道怎么才能得到这个MyBatils对象了,这也就是怎么注入MyBatils对象到Spring中。

@Component
public class UserService {
    @Autowired
    UserMapper userMapper;
    public void test(){
        System.out.println(userMapper.get());
    }
}
public class LuoGeBeanFactory implements FactoryBean {
    public Object getObject() throws Exception {
        // 想要使用UserMapper对象, 我们就需要进行代理,这样我们就得到了这个代理对象。
        Object o = Proxy.newProxyInstance(UserMapper.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method.getName());
                return null;
            }
        });
        return o;
    }
    
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}

@ComponentScan("com.test")
public class LuoGeApplaction implements InstantiationAwareBeanPostProcessor {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(LuoGeApplaction.cla***Spring

        //表示用来定义bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(LuoGeBeanFactory.class);
        //将user对象注入到这个beanDefintion中。
        context.registerBeanDefinition("xxx",beanDefinition);

        context.refresh();

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

get
null
这里的get就是我们调用的那个方法,这个null是这个方法返回的null;



 

这里的null其实是userService对象,但是我们输出这个对象需要调用对象的toString方法。

              <dependency>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                    <version>2.0.6</version>
                </dependency>
这个jar包里面其实也就是在做我们刚才FactoryBean的事,但是我们发现了这个方法里面的UserService.class是定死了的Proxy.newProxyInstance(UserMapper.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() 问题又出现了,难道我们只能用这一个类吗?

public interface PeopleMapper {
    User set();
}

public class LuoImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    List<Class> list = new ArrayList<Class>();
        list.add(PeopleMapper.class);
        list.add(UserMapper.class);

        for (Class aClass : list) {
            //表示用来定义bean
            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
            beanDefinition.setBeanClass(LuoGeBeanFactory.class);
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(aClass);
            //将user对象注入到这个beanDefintion中。
            registry.registerBeanDefinition(aClass.getName(),beanDefinition);
        }
    }
        
    }
}

@ComponentScan("com.test")
@Import(LuoImportBeanDefinitionRegistrar.class)
public class LuoGeApplaction implements InstantiationAwareBeanPostProcessor {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(LuoGeApplaction.cla***Spring
            context.refresh();

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


        }
}

null;
我们有了第二个Mapper的时候,我们就不能再把其中的类写死了,我们将它写成一个变量,再调用有参构造来注入它,当然我们再把除了启动Spring的代码移出去,移到ImportBeanDefinitionRegistrar类上,这也是我们启动前执行的类,将它通过@Imput注解将它注入到主要执行的代码中,他就可以实现不同的Mapper对象注入了。当然我们把所有需要的Mapper类都放到List集合中进行遍历就可以实现伪自动注入了。现在我么又引出一个问题,怎么才能扫描储所有的Mapper对象?

就是通过beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(aClass)方法把对应的类名传给LuoGeBeanFactory的有参构造进行赋值,但是因为我们在LuoGeBeanFactory存的就是mapper,再把beanDefinition的BeanClassName设置为原来的就可以了。

package com.mybatils.spring;

import com.test.mapper.PeopleMapper;
import com.test.mapper.UserMapper;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class LuoImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        // 1 扫描 2 扫描路径
        String path = "com.test.mapper";
        //扫描注册表
        LuoMapperScanner luoMapperScanner = new LuoMapperScanner(registry);
        luoMapperScanner.addIncludeFilter(new TypeFilter() {
            //由于这个scan扫描默认会排除一些东西,return true相当于不排除的意思,支持所有
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });

        int sacn = luoMapperScanner.scan(path);// 2个mapper
        System.out.println(sacn);

    }
}


package com.mybatils.spring;


import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.Set;

public class LuoMapperScanner extends ClassPathBeanDefinitionScanner {
    //Spring 的扫描器
    public LuoMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 这里得到beanDefinitionHolders就是扫描了Mapper
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);

        //我们得到的还是Mapper的接口,并不能得到对象 我们已经得到BeanFinition 并把他注入进去了
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();

            //设置LuoGeBeanFactory类构造方法的参数值,将类名传入进行代理,得到代理对象
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            //遍历出来的BeanClass是不对的 是个接口  我们修改它成为它所对应的class名因为我们一开始就是需要beanClass名称才能得到对应的接口类
            beanDefinition.setBeanClassName(LuoGeBeanFactory.class.getName());
        }
        return beanDefinitionHolders;
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        //我们只需要找到属于接口的类跟Spring恰恰相反,Spring需要的是可以实现的类。
        return beanDefinition.getMetadata().isInterface();
    }
}

package com.mybatils.spring;

import com.sun.org.apache.regexp.internal.RE;
import com.test.mapper.UserMapper;
import com.test.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class LuoGeBeanFactory implements FactoryBean  {

    private Class mapperClass;

    private SqlSession sqlSession;


    public LuoGeBeanFactory(Class mapperClass) {
        this.mapperClass = mapperClass;
    }
    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {

        this.sqlSession = sqlSessionFactory.openSession();
    }
    public Object getObject() throws Exception {
//         //想要使用UserMapper对象, 我们就需要进行代理,这样我们就得到了这个代理对象。
//        Object o = Proxy.newProxyInstance(UserMapper.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                System.out.println(method.getName());
//                return null;
//            }
//        });
//        return o;
        //直接通过sqlSession得到mapper
        return sqlSession.getMapper(mapperClass);
    }


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


package com.test;

import com.mybatils.spring.LuoGeBeanFactory;
import com.mybatils.spring.LuoImportBeanDefinitionRegistrar;
import com.test.mapper.UserMapper;
import com.test.pojo.User;
import com.test.service.UserService;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;

import java.io.IOException;
import java.io.InputStream;

@ComponentScan("com.test")
@Import(LuoImportBeanDefinitionRegistrar.class)
public class LuoGeApplaction implements InstantiationAwareBeanPostProcessor {

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {
        //只需要的到一个sqlSessionFactory 文件可以随便写
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }

    public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
            context.register(LuoGeApplaction.cla***Spring
            context.refrJ();

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


        }
}


people
people

通过LuoMapperScanner调用scan底层就是doScan方法进行对这个包的扫描的到我们想要的Mapper对象,再dosacn方法中我们我们取出本来就存入了beanDefinition的BeanClass名字(),再将它设置为原来的名字设置为beanDefinitionHolders(这里得到beanDefinitionHolders就是扫描了Mapper),这里我们就得到了mapper层的所有接口类了,所以scan的值是2,这里我们再通过方法的到SqlSessionFactory对象,SqlSessionFactory就可以直接getMapper了,这就是我们的Spring Mybatis的整合基本原理。
————————————————
版权声明:本文为CSDN博主「本来写bug却写成了程序」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_57560984/article/details/120442474

全部评论

(0) 回帖
加载中...
话题 回帖

近期热帖

热门推荐