从Bean的装配理解Spring框架

Posted JF Coder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从Bean的装配理解Spring框架相关的知识,希望对你有一定的参考价值。

阅读此文前,可以参考这篇文章:
Spring源码解析


基于XML装配Bean

applicationContext.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="helloSpring" class="com.gjf.HelloSpring">
    <!--id表示bean实例的名称 class是这个bean的类型,也是需要实例化bean的类-->
    <!--将value的值赋值给who属性"/>-->
    <property name="who" value="Spring"/>
</bean>
</beans>
  1. 可以通过ClassPathXmlApplicationContext加载applicationContext.xml文件
public class HelloSpringTest {
    @Test
    public void test() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        HelloSpring helloSpring = (HelloSpring)applicationContext.getBean("helloSpring");
        helloSpring.print();
    }
}
  1. ClassPathXmlApplicationContext源码
	/**
      独立的XML应用程序上下文,从类路径中获取上下文定义文件
      是一个简单的一站式便利ApplicationContext
	 */
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
	@Nullable
	private Resource[] configResources;
	/**
     为bean样式的配置创建一个新的ClassPathXmlApplicationContext
	 * @see #setConfigLocation
	 * @see #setConfigLocations
	 * @see #afterPropertiesSet()
	 */
	public ClassPathXmlApplicationContext() {
	}

	/**
    创建一个新的ClassPathXmlApplicationContext,
    从给定的XML文件中加载定义,并自动刷新上下文。
	 * @param configLocation resource location
	 * @throws BeansException if context creation failed
	 */
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

ClassPathXmlApplicationContext的UML关系图,如果读过spring的源码,可能发现很多熟悉的类或者接口;

可以参考这篇文章:Spring源码解析

BeanFactory接口:Spring的IOC容器核心接口,它的职责包括,实例化,有很多的实现类;

ApplicationContext接口:用于访问应用程序组件的Bean工厂方法,以通用方式加载文件资源的能力等

(Spring的上下文,我简单理解就是spring的当前运行的环境,也可以理解是spring可以利用的资源。)

ApplicationContext有两个主要的实现类:ClassPathXmlApplicationContext:默认从类路径加载配置文件,还有FileSystemXmlApplicationContext:默认从文件系统中装载配置文件

在这里插入图片描述
理清spring创建定制Bean的整个过程

Bean的装配方式:

  1. 基于XML的装配
  2. 基于注解的装配
  3. 自动装配
<!--创建Bean的三种方式 -->
    <!-- 第一种方式:使用默认构造函数创建。
            在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
            采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
    -->

    <!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
    <bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
    <bean id="accountService" factory-bean="instanceFactory"
          factory-method="getAccountService"></bean>
    -->

    <!-- 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
    <bean id="accountService" class="com.itheima.factory.StaticFactory" 
    factory-method="getAccountService"></bean>
    -->
  <!-- bean的作用范围调整
        bean标签的scope属性:
            作用:用于指定bean的作用范围
            取值: 常用的就是单例的和多例的
                singleton:单例的(默认值)
                prototype:多例的
                request:作用于web应用的请求范围
                session:作用于web应用的会话范围
                global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="prototype"></bean>
    -->

创建实例对象不在是调用者来创建而是交给spring(控制反转),在Spring框架实例化Bean的过程中,首先调用Bean默认的构造方法来实例化Bean对象,然后通过反射的方式调用setter方法注入属性值(依赖注入)

依赖注入时,要求Bean必须满足下列要求

  1. 提供一个默认的无参构造方法
  2. 需要为注入的属性提供对应的setter方法

基于注解装配Bean

减少xml文件的使用,引入注解

Spring常用的注解

定义bean的注解说明
@Component描述spring中的bean
@Repository用于数据访问层(Dao),标识为spring的bean,功能与@Component相似
@Service通常用于业务层(Service层),将类标识为spring的bean,功能与@Component相似
@Controller通常作用于控制层(Controller层),将类标识为spring的bean,功能与@Component相似
  • 找@Repository的源码看看
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {

	/**
	该值可能表示建议使用逻辑组件名称,如果是自动检测到的组件,
	则将其转换为Spring bean. 
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}
Bean组件装配注解说明
@Autowired用于对bean的属性变量,构造方法进行标注,按照默认bean的类型完成自动配置工作
@Resource用于对bean的属性变量,构造方法进行标注,按照默认bean的实例名称完成自动配置工作
@Qualifier与@Autowired配合使用,会默认的按bean类型装配修改为按实例名称装配,实例名称由@Qualifier参数指定
//@Autowired事例
@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired  //默认按照类型匹配
    private UserDao userDao;
/*    @Override      使用@Autowired 直接注入属性,可以省略setter方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }*/
}
  • 点进@Autowired,AutowiredAnnotationBeanPostProcessor 进去看
 /* @author Juergen Hoeller
 * @author Mark Fisher
 * @author Sam Brannen
 * @since 2.5
 * @see AutowiredAnnotationBeanPostProcessor  //see see看
 * @see Qualifier
 * @see Value
 */
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
	boolean required() default true;

}
/**
为Spring的标准{@link Autowired @Autowired}和
{@link Value @Value}注释创建一个新的{@code AutowiredAnnotationBeanPostProcessor}
还支持JSR-330的{@link javax.inject.Inject @Inject}批注(如果可用)
	 */
	@SuppressWarnings("unchecked")
	public AutowiredAnnotationBeanPostProcessor() {
		this.autowiredAnnotationTypes.add(Autowired.class);
		this.autowiredAnnotationTypes.add(Value.class);
		try {
			this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
					ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
			logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}
	/**
	设置“自动装配”注释类型,以用于构造函数,字段,setter方法和任意配置方法。 
	默认的自动装配注释类型是Spring提供的{@link Autowired @Autowired}和{@link Value @Value}注释以及 JSR-330的{@link javax.inject.Inject @Inject}注释, 如果可供使用的话。 * <p>存在此setter属性,以便开发人员可以提供自己的*(非特定于Spring的)批注类型,以指示应该自动装配成员。
	 */
	public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {
		Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");
		this.autowiredAnnotationTypes.clear();
		this.autowiredAnnotationTypes.add(autowiredAnnotationType);
	}

发现什么?spring真强大!哈哈哈!

{@link Autowired @Autowired}和{@link Value @Value}注释创建一个新的{@code AutowiredAnnotationBeanPostProcessor},熟悉的:BeanPostProcessor

就讲这些吧,希望可以给初学Spring的猿提供捷径吧
一键三连收藏


以上是关于从Bean的装配理解Spring框架的主要内容,如果未能解决你的问题,请参考以下文章

从Bean的装配理解Spring框架

Spring框架第一篇之Bean的装配

Spring 框架学习---- bean自动装配注解开发

Spring框架学习:Spring @Autowired实现自动装配

Spring5 Java代码装配Bean

spring技术核心概念纪要