一起学SF框架系列5.2-spring-Beans-bean的元数据配置

  IoC容器通过定义bean的元数据来感知bean,本节主要讲述Bean的元数据配置模式。Bean的元数据配置模式由三种:xml模式、java代码模式和注解模式。xml模式是SF初始就采用的模式,是个完整的体系;实际上,java代码模式和注解模式是否被采用也需要通过xml模式进行定义。Java代码模式主要是通过专门的类来声明Bean和Bean之间的关系,注解模式是在Java代码中通过注解进行Bean关系定义。三种模式不是截然分开的,在实际使用过程中可以混用。

xml模式

  xml模式是在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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- id:bean的唯一识别标识;class:完全限定的类名(即含包名)-->
	<bean id="..." class="...">
		<!-- bean间协作或初始化等配置信息 -->
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions go here -->

</beans>

样例1:

<?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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="accountDao"
		class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>
	<!-- more bean definitions for data access objects go here -->

</beans>

样例2:

<?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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- services -->
	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
	 	#属性类引用关系
		<property name="accountDao" ref="accountDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>
	<!-- more bean definitions for services go here -->

</beans>

组合格式

可在多个配置文件中进行各自配置,然后组合在一起。

<beans>
	<!-- 通过import把分开定义的配置组合在一起 -->
	<import resource="services.xml"/>
	<import resource="resources/messageSource.xml"/>
	<import resource="/resources/themeSource.xml"/>

	<bean id="bean1" class="..."/>
	<bean id="bean2" class="..."/>
</beans>

注意要点:import文件的位置路径是相对于执行导入的定义文件目录或类路径位置

配置文件位置

配置文件一般存放在ClassPath可寻址的位置,支持其它方式如:
file:配置文件绝对路径

配置文件导入

ClassPath方式导入

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

1、配置文件必须位于ClassPath可寻址的位置。
2、可多个文件导入,类似配置的组合格式。

FileSystem方式导入

ApplicationContext context = new FileSystemXmlApplicationContext("/resource/services.xml");

1、位置必须相对于应用根目录位置。
2、路径即使以"/"开始,也是相对于应用根目录。

XmlBeanDefinitionReader方式

用GenericApplicationContext 结合XmlBeanDefinitionReader阅读器使用导入,该种方式非常灵活。

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

java代码模式

Java代码模式配置Bean,就是通过特定注解(核心是@Bean和@Configuration)实现Bean的相关定义。

@Bean和@Configuration

1、@Bean注解用于指示一个方法实例化、配置和初始化一个新的对象。相当于xml模式下的<bean …/>元素
2、@Configuration注解一个类,表明该类的主要目就是作为 bean 定义的来源。 此外,@Configuration注解的类中,允许通过调用同一类中的其他@Bean方法来定义 bean 间依赖关系。

简单Bean定义

@Configuration
public class AppConfig {

	@Bean
	public MyServiceImpl myService() {
		return new MyServiceImpl();
	}
}

AppConfig 相当于xml模式下的xml定义文件。
@Bean注解的MyServiceImpl相当于xml的如下定义:

<beans>
	<bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

注意:@Bean方法名对应示例出来Bean的id
虽然@Bean可在未使用@Configuration 注释的类中声明(此时不能声明 bean间的依赖关系),但在常见的场景中,@Bean 方法将在@Configuration 类中声明,保证Bean定义及相互间引用关系的完整。

Bean引用关系

@Configuration
public class AppConfig {

	@Bean
	public ClientService clientService1() {
		ClientServiceImpl clientService = new ClientServiceImpl();
		clientService.setClientDao(clientDao());
		return clientService;
	}

	@Bean
	public ClientService clientService2() {
		ClientServiceImpl clientService = new ClientServiceImpl();
		clientService.setClientDao(clientDao());
		return clientService;
	}

	@Bean
	public ClientDao clientDao() {
		return new ClientDaoImpl();
	}
}

1、实例化时bean-clientService1和clientService2都引用了实例化Bean-clientDao。
2、代码中clientDao()创建了一个新的 ClientDaoImpl 实例并返回它,在 clientService1() 中被调用一次,在 clientService2() 中被调用一次,正常理解clientDao()是有两个实例(每个服务一个)。但实际上是只有一个,因为Spring 中实例化的 bean默认是单实例的。

Bean配置初始化

用AnnotationConfigApplicationContext进行java代码模式的初始化,代码示例如下:

public static void main(String[] args) {
	ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
	MyService myService = ctx.getBean(MyService.class);
	myService.doStuff();
}

Bean配置组合

下面代码演示多个Bean定义类如何组合:

@Configuration
public class ServiceConfig {

	@Autowired
	private AccountRepository accountRepository;

	@Bean
	public TransferService transferService() {
		return new TransferServiceImpl(accountRepository);
	}
}

@Configuration
public class RepositoryConfig {

	private final DataSource dataSource;

	public RepositoryConfig(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	@Bean
	public AccountRepository accountRepository() {
		return new JdbcAccountRepository(dataSource);
	}
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

	@Bean
	public DataSource dataSource() {
		// return new DataSource
	}
}

public static void main(String[] args) {
	ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
	// everything wires up across configuration classes...
	TransferService transferService = ctx.getBean(TransferService.class);
	transferService.transfer(100.00, "A123", "C456");
}

1、SystemTestConfig 通过@Import注解组合了ServiceConfig、RepositoryConfig
2、ServiceConfig通过@Autowired自动注入RepositoryConfig中的Bean实例accountRepository。

补充说明

context:annotation-config/ 元素隐式注册了以下后处理器:
ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor、EventListenerMethodProcessor
由这些后处理器完成注解配置解析

注解模式

  注解模式是通过在相关类、方法或字段声明上使用注解将配置移到组件类本身来完成元数据配置。spring同时支持JSR-250和JSR-330注解规范。
  注解模式使配置更简单,但同时配置也更分散。

配置注解模式

配置文件中加入如下配置:

	<!-- 注解模式:配置bean扫描路径(注:自动包含子路径) -->
	<context:component-scan base-package="com.learnsf.main,com.learnsf.service"/>

Bean注解

在类前加上@Component,表示当前类是个bean。当注解作用在类上时,表明这些类是由spring容器自动管理,不需要在xml或@Configuration类中定义。为了便捷且统一处理,Spring针对主流的分层结构提供通用Bean注解:
@Controller:表示当前类是控制类。
@Service:表示当前类是服务类。
@Repository:表示当前类是数据类。
这三个注解可看作@Component引申的特殊注解,当不好归类到上述三种类时,用@Component标注,表示一个由Spring容器管理的单例bean。
关于bean的名称,默认为类名且第一个字母小写。如果需要特别名称,采用@Component(“thisIsBeanName”)模式配置。

bean内使用的注解

@Autowired

1、@Autowired表示自动装配,相当于JSR-330中的@Inject。
2、@Autowired位置:
在类构造函数前:表示类自动装配。注解模式下,类只有一个默认构造函数,不需要加@Autowired也表示自动装配;如果没有默认构造函数,则至少一个构造函数前需加@Autowired,才能自动装配。
在属性变量前:表示自动装配依赖类。
在方法前:表示自动装配依赖类。
在参数前:表示自动装配依赖参数类。
在特殊接口前:将 @Autowired 用于如下接口:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher 和 MessageSource。容器会自动装配合适Bean。
3、@Autowired、@Inject、@Value 和@Resource 注解均在 Spring BeanPostProcessor 实现处理。 这意味着不能在自己的 BeanPostProcessor 或 BeanFactoryPostProcessor中使用这些注解。

@Primary

当@Autowired注入的类有多个Bean实现时,Bean定义时用@Primary表示优先使用该Bean

@Qualifier

当@Autowired注入的类有多个Bean实现时,Bean定义时用@Qualifier的限定词表示使用该Bean。

@Resource

@Resource在JSR-250中定义。
@Resource(name=xx):表示按指定name的bean来注入。如果未明确指定名称(仅@Resource),则默认名称派生自属性名称或 setter 方法。 在属性前注解,它采用属性名称。 在 setter 方法前注解,它采用要设置的 bean 属性名称。

@Autowired与@Resource区别

@Autowired默认按byType自动装配,而@Resource默认byName自动装配。
@Autowired只包含一个参数:required,表示是否开启自动准入,默认是true。而@Resource包含七个参数,其中最重要的两个参数是:name 和 type。
@Autowired如果要使用byName,需要使用@Qualifier一起配合。而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配。
@Autowired能够用在:构造器、方法、参数、成员变量和注解上,而@Resource能用在:类、成员变量和方法上。
@Autowired是spring定义的注解,而@Resource是JSR-250定义的注解。

@Value

@Value 通常用于注入外部化属性。@ Value属性注入功能可以分为两种:通过配置文件进行属性注入和通过非配置文件进行属性注入法:
(1)@Value(“${}”):可以获取对应属性文件(默认加载的application.yml)中定义的属性值。
(2)@Value(“#{}”):表示 通常用SpEL来获取 bean 的属性,或者调用 bean 的某个方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐享技术

每一个打赏,都是对我最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值