欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

挖一挖@Bean这个东西

程序员文章站 2022-03-02 23:44:14
有Bean得治 任何一个正常程序的访问都会在内存中创建非常多的对象,对象与对象之间还会出现很多依赖关系(一个处理业务逻辑的类中几乎都会使用到别的类的实例),一般的做法都是使用new关键字来创建对象,对于多次重复使用的对象会采用单例模式来设计。 但在Spring中却不是这样,Spring框架使用了一个 ......

有bean得治

  任何一个正常程序的访问都会在内存中创建非常多的对象,对象与对象之间还会出现很多依赖关系(一个处理业务逻辑的类中几乎都会使用到别的类的实例),一般的做法都是使用new关键字来创建对象,对于多次重复使用的对象会采用单例模式来设计。

  但在spring中却不是这样,spring框架使用了一个容器对这些对象进行管理,每一个需要被管理的对象被称为bean,而管理这些bean的容器,被称为ioc容器。

  控制反转(ioc)在是一种通过描述来生成或者获取对象的技术,在spring boot中,我们经常是通过注解来创建对象,这里只谈注解,无视xml。

  spring boot在启动的过程中,会去扫描需要被管理的bean,将bean装载到ioc容器中,根据依赖关系进行实例化对象,最后进行依赖注入。也就是说,在项目启动完成后,所有的bean都已经实例化完成,并已在相应的地方注入完成,访问程序使用到的这些对象都只是在直接调用对象实例,并不会出现一个new的过程,因为这些对象在项目启动的时候就已经都被new出来了。

  bean的创建方式有很多种,最常用的是@component,@service,@repository等等直接放在类头上的注解,都是一些标记,用于被收集后反射再实例化最终赋值达到注入的目的,可了解的应该就是其中的一些附带规则:条件装配,就是如果存在某个bean时(也可以判断不存在时)再装配当前这个bean,不过条件装配我觉得应用场景并不常见。

  这里主要是要挖一挖@bean这个注解的使用。

用@bean创建bean

  @bean注解是只能用在方法上,标志该方法需要创建一个bean,方法返回的对象就是创建bean的目标对象。

建一个user实体类:

public class user {
    private int id = 2;
    private string name = "我是user类的小光";
    private string sex = "我是难的";

    public int getid() {
        return id;
    }

    public void setid(int id) {
        this.id = id;
    }

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }

    public string getsex() {
        return sex;
    }

    public void setsex(string sex) {
        this.sex = sex;
    }

    @override
    public string tostring() {
        return "user{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

 

示例:

@configuration  
public class config {
    @bean
    public string aaa(){
        return "你大爷";
    }

    @bean
    public user bbb(){
        return new user();
    }
}  

  这个config类,创建了两个bean,创建的对象一个是string对象一个是user对象,可以是任何对象,我这里为了更加直白的表达“bean”是什么东西,特意使用了string来做例子。

当然了  bean的名字是可以定的 以下三种定义方式都可以:

    @bean(name = "aaa")
    @bean("aaa")
    @bean

第三种方式没有指定名字,那么框架会将方法名作为bean的名字,注意:是方法原名,不会是小驼峰,只有应用在类上的注解创建的bean才会是小驼峰,@bean是方法上的注解。

你的脑补绝对有用

  此时,你可以脑补一下框架是怎么创建bean的:

        hashmap map = new hashmap();
        map.put("aaa",new string("你大爷"));
        map.put("bbb",new user());

  所谓ioc容器,就是一个集合,装了很多对象,你要用哪个对象,spring就会从集合里取给你。

----->当然了,虽然你的脑补不一定完全正确,但是你的脑补绝对有用。

@bean注解受不受@componentscan的影响?

  @componentscan注解定义扫描路径,也就是说,spring boot只会扫描指定路径之内的类,遇到特殊注解就会开始进行bean的收集工作。

  在spring boot的启动类main方法上有@springbootapplication注解,点进去之后可以看到它里面包含的有@componentscan,所以尽管我们没有手动指定扫描范围,但是默认是以启动类所在的包作为一个扫描范围。

  但这里要说明的是,@componentscan这个注解,它是用来约束@configuration,@controller,@service,@repository,@component等作用在类上注解,但是它管不了@bean注解,只要项目中有@bean注解,即使身处启动类的外层,不在@componentscan的扫描范围之内,该bean也会存在,只是没有被扫描装配,也就是可以获取,但无法注入。

是否一定要和@configuration一起用? 

  我的答案是:是的!

  如果你没有加@configuration注解,那么spring将不会扫描这个类,但是你后期获取该bean的时候,spring可以找到它,也就是说,如果没有加@configuration注解,那么项目启动后是没有该bean的,只有当你获取该bean的时候,才会进行实例化。

获取你的bean

        annotationconfigapplicationcontext context = new annotationconfigapplicationcontext(config.class);
        object aaa = context.getbean("aaa");
        system.out.println(aaa.tostring());

        object bbb = context.getbean("bb");
        system.out.println(bbb.tostring()); 

该示例代码获取的是config类中的aaa和bbb两个bean。

  注意,它并不是获取容器中的bean,它是根据你提供的class和bean名称跑去执行了一下方法,新new了一个对象给你,再有,这个bean名称必须用原名,大小写不打折的。

  小提示:无论类的头上有没有@configuration注解,该方式都可以成功,当然,如果类的头上有@configuration注解,那么该bean的返回对象可以直接在别处进行注入。

 

如果你要获取类上的bean,可以采用下面这个工具类来获取:

@component
public class springutil implements applicationcontextaware {

    private static applicationcontext applicationcontext = null;

    @override
    public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
        if (null == springutil.applicationcontext) {
            springutil.applicationcontext = applicationcontext;
        }
    }

    // 获取applicationcontext
    public static applicationcontext getapplicationcontext() {
        return applicationcontext;
    }

    // 通过name获取 bean.
    public static object getbean(string name) {
        return getapplicationcontext().getbean(name);
    }

    // 通过class获取bean.
    public static <t> t getbean(class<t> clazz) {
        return getapplicationcontext().getbean(clazz);
    }

    // 通过name,以及clazz返回指定的bean
    public static <t> t getbean(string name, class<t> clazz) {
        return getapplicationcontext().getbean(name, clazz);
    }
}