文章目录

    • Java Bean 和 Spring Bean
    • Java Bean
    • Spring Bean
      • XML创建bean
      • @Bean创建Bean
      • @CompantScan创建Bean
      • 编程式BeanDefinition
      • FactoryBean 构建bean
      • Supplier 定义bean
    • 代码参考

Java Bean 和 Spring Bean

Bean 就是对象。

不管是 Java Bean 还是 Spring Bean,都是为了获取实例化对象。其中的区别,本章博客采取代码案例说明。

Java Bean

Java Bean 即 Java 对象,在Java 中,定义一个对象采取new实例化操作。

class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}
public class Test { 
    public static void main(String[] args) { 
        User user = new User();
        user.setName("香蕉");
        System.out.println(user.getName());
    }
}

Spring Bean

测试使用 Spring Bean,则需要引入Spring依赖文件。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.13.RELEASE</version>
</dependency>

XML创建bean

创建一个User.java类

package cn.linkpower.xml;

public class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}

resources文件下创建spring.xml文件,并配置指定的Bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 1、定义bean(根据User中的构造方法生成bean对象)-->
    <bean id="userBean" class="cn.linkpower.xml.User"></bean>
</beans>

创建测试类,将指定的spring.xml文件加入至Spring容器中,实现对象的获取,设置值和调用等。

package cn.linkpower.xml;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test { 
    public static void main(String[] args) { 
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //classPathXmlApplicationContext.setConfigLocation("spring.xml");

        User userBean = classPathXmlApplicationContext.getBean("userBean", User.class);
        userBean.setName("香蕉");
        System.out.println(userBean.getName());

		  // 验证Spring的bean是单例!
// User userBean2 = classPathXmlApplicationContext.getBean("userBean", User.class);
// userBean2.setName("香蕉2");
// System.out.println(userBean.getName());
// System.out.println(userBean2.getName());
// System.out.println(userBean.getName());
    }
}

@Bean创建Bean

上面的操作,根据在xml中定义配置指定的bean对象,采取org.springframework.context.support.ClassPathXmlApplicationContext将其加载至spring容器中,达到对象的生成和引用操作。

同时,也可以采取@Bean实现对象的生成。

package cn.linkpower.beans;

import org.springframework.context.annotation.Bean;

public class UserConfig { 
	/** * 采取 @Bean 的方式,构建一个 bean对象;<br/> * 相当于 <bean id="getUser" class="cn.linkpower.beans.User" /> * @return */
    @Bean
    public User getUser(){ 
        return new User();
    }
}

使用AnnotationConfigApplicationContext,将其加载至容器中。
测试类编写

package cn.linkpower.beans;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test { 
    public static void main(String[] args) { 
        // 构建容器
        //AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        // 加载、注册配置类
       // annotationConfigApplicationContext.register(UserConfig.class);
        //annotationConfigApplicationContext.refresh();
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(UserConfig.class);
        // 获取对象
        User getUser = annotationConfigApplicationContext.getBean("getUser", User.class);

        getUser.setName("banana");

        System.out.println(getUser.getName());
    }
}

@CompantScan创建Bean

上述的两种方式,都需要配置或者编写配置类的方式,定义或构建bean。如果对象过多,则需要配置的就较多。

除此之外,还能根据扫描操作实现类的定义操作。

编写扫描操作工具类(创建一个类,添加注解操作即可),当然,SpringBoot项目默认扫扫描启动类下目录:

package cn.linkpower.beanScan;

import org.springframework.context.annotation.ComponentScan;

/** * @ComponentScan 注解,扫描的是带有 @Component 的类,将其解析加载至spring容器中 */
@ComponentScan("cn.linkpower.beanScan")
public class UserConfigScan { 
}

由于使用@ComponentScan注解,是扫描指定路径下,携带有@Component标注的类,将其加载至Spring容器中,所以如果需要将类加载至Spring容器中,则需要在指定的类上添加Component注解。

package cn.linkpower.beanScan;

import org.springframework.stereotype.Component;

@Component
public class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}

编写测试类:

package cn.linkpower.beanScan;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test { 
    public static void main(String[] args) { 
    	// 这里主要是加载带有 @ComponentScan 注解的类,实现扫描 @Component 显示或隐式标注的类
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(UserConfigScan.class);
        // 默认类名驼峰规范,所以此处从容器获取类,使用user
        User user = applicationContext.getBean("user", User.class);
        System.out.println(user);
    }
}

在Springboot中就广泛使用到@ComponentScan。其次,类似@Service等注解中也有@Component的注解标注。

编程式BeanDefinition

在Spring构建bean对象时,采取xml 定义 bean@Bean 注解@Compant 注解等方式,都属于声明式创建bean对象。

Spring也支持编程式创建实例对象,如下所示:

需要Spring构建实例化bean的类上无注解

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}

public class Test { 
    public static void main(String[] args) { 
        // 创建容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 执行一次refresh,否则报错
        applicationContext.refresh();
        // 描述一个bean
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(User.class);

        // 将描述的bean,设置别名称,放入容器中
        applicationContext.registerBeanDefinition("userBeanObj",beanDefinition);

        // 从容器中获取bean
        User userBeanObj = applicationContext.getBean("userBeanObj", User.class);
        System.out.println(userBeanObj);

    }
}

在 Spring 源码中,不管是使用@Component@Bean还是xml 配置<bean />等,其底层的实现依旧还是采取的BeanDefinition进行编程式构建。

除此之外,在BeanDefinition中,还有其他属性参数可供类的设置,如单例、多例等。

FactoryBean 构建bean

创建一个需要使用Spring实例化的类(无@Component注解):

package cn.linkpower.factoryBean;

public class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}

编写一个工厂类,为了生成bean:

package cn.linkpower.factoryBean;

import org.springframework.beans.factory.FactoryBean;

public class UserFactory implements FactoryBean { 

    /** * 生成对象 * @return * @throws Exception */
    public Object getObject() throws Exception { 

        return new User();
    }

    /** * 对象的类型 * @return */
    public Class<?> getObjectType() { 
        return User.class;
    }
}

编写测试类:

package cn.linkpower.factoryBean;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test { 
    public static void main(String[] args) { 
        // 1、构建容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.refresh();
        // 2、定义bean的修饰类
        AbstractBeanDefinition abstractBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        // 添加一个类进去
        abstractBeanDefinition.setBeanClass(UserFactory.class);
        // 3、将已修饰的类放入容器中
        applicationContext.registerBeanDefinition("userFactoryTest",abstractBeanDefinition);
        //4、获取类
        User user = applicationContext.getBean("userFactoryTest",User.class);
        System.out.println(user);
        
        
        // 这个是报错的!
        //System.out.println(applicationContext.getBean("userFactoryTest",UserFactory.class));
        
        // 如果想获取 UserFactory 对象,则需要 名称写为 &userFactoryTest
        //System.out.println(applicationContext.getBean("&userFactoryTest",UserFactory.class));
    }
}

[注意:]

使用org.springframework.beans.factory.FactoryBean修饰产生的bean,其实spring容器会将其生成两个bean对象。
userFactoryTest—> User 对象bean
&userFactoryTest—>UserFactory 类的对象bean

使用 org.springframework.beans.factory.FactoryBeangetObject()间接定义了一个bean。

Supplier 定义bean

在Spring框架中,存在使用Supplier构建bean的操作,在初始化生成bean时,可以通过Supplier类生成一个类初始的数据。其案例信息如下所示:

package cn.linkpower.supplier;

public class User { 
    private String name;

    public String getName() { 
        return name;
    }

    public void setName(String name) { 
        this.name = name;
    }
}

新建测试类:

package cn.linkpower.supplier;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.function.Supplier;

public class Test { 
    public static void main(String[] args) { 
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.refresh();

        // 通过这种方式 注册bean
        //applicationContext.registerBean(User.class);

        applicationContext.registerBean(User.class, new Supplier<User>() { 
            public User get() { 
                User user = new User();
                user.setName("banana");
                return user;
            }
        });

        User user = applicationContext.getBean("user", User.class);
        System.out.println(user.getName());

    }
}

代码参考

github 测试代码地址

本文地址:https://blog.csdn.net/qq_38322527/article/details/113946325