我的Java Web之路 - Spring IoC(3)- 使用注解生产Bean

本文介绍如何在Spring框架中使用component-scan标记和@Service、@Repository等注解,替代XML配置,实现组件自动扫描与Bean定义。通过具体代码示例,详细解释了自动装配与自动扫描的区别及应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

前面的文章介绍了如何使用注解来实现Bean的自动装配(依赖注入),但还需要XML文档并且使用<bean>标记来告诉Spring IoC容器要生成哪些Bean。

本篇文章则继续介绍如何进一步简化XML文档,使用注解来生产Bean。

移除XML中的Bean定义并启用组件扫描:component-scan标记

spring-ioc-test.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		https://www.springframework.org/schema/beans/spring-beans.xsd 
		http://www.springframework.org/schema/context 
		https://www.springframework.org/schema/context/spring-context.xsd">
	
	<context:component-scan base-package="test" />

</beans>

可以看到,现在的XML文件中不仅没有了Bean的依赖注入,甚至连Bean的定义都没有了。

与上一篇文章唯一的不同在于把之前的启用自动装配的标记<annotation-config>标记,替换成了启用自动扫描的标记<component-scan>

首先,<component-scan>标记隐含地包含了<annotation-config>标记的功能,也就是说启用了自动扫描,也就启用了自动装配。

其次,它有一个属性base-package,用于设置需要自动扫描的包,本例中所有组件都在test包及其子包下面。

Bean定义注解:@Service

@Service注解的作用其实就相当于XML文档中<bean>标记的作用,就是告诉Spring IoC容器这里有一个Bean定义,运行时要生成一个以此类为类型的Bean。

不过,@Service这个注解可以从名字上看出该Bean的作用是一个服务层Bean,在语义上更清晰。

ServiceA.java

package test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import test.repository.RepositoryA;

@Service
public class ServiceA {

	private ServiceB serviceB;
	private RepositoryA repositoryA;
	
	@Autowired
	public ServiceA (ServiceB serviceB, RepositoryA repositoryA) {
		this.serviceB = serviceB;
		this.repositoryA = repositoryA;
	}
	
	public void doWork() {
		System.out.println("ServiceA doWork start");
		serviceB.doWork();
		repositoryA.save();
		System.out.println("ServiceA doWork end");
	}
}

与之前的ServiceA唯一的不同,就是在类定义之前多了一个注解@Service

同理,在ServiceB类也加上@Service注解即可。

ServiceB.java

package test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import test.repository.RepositoryB;

@Service
public class ServiceB {

	@Autowired
	private RepositoryB repositoyB;
	
	public void doWork() {
		System.out.println("ServiceB doWork start");
		repositoyB.update();
		System.out.println("ServiceB doWork end");
	}
}

Bean定义注解:@Repository

@Repository注解的作用类似于@Service,也是相当于XML文档中<bean>标记的作用,就是告诉Spring IoC容器这里有一个Bean定义,运行时要生成一个以此类为类型的Bean。

不过,@Repository这个注解可以从名字上看出该Bean的作用是一个持久层(就是数据访问层)Bean,在语义上更清晰。

RepositoryA.java

package test.repository;

import org.springframework.stereotype.Repository;

@Repository
public class RepositoryA {

	public void save() {
		System.out.println("RepositoryA save ...");
	}
}

与之前的RepositoryA唯一的不同,就是在类定义之前多了一个注解@Repository

同理,在RepositoryB类也加上@Repository注解即可。

RepositoryB.java

package test.repository;

import org.springframework.stereotype.Repository;

@Repository
public class RepositoryB {

	public void update() {
		System.out.println("RepositoryB update ...");
	}
}

验证

SpringMain.java:

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import test.service.ServiceA;

public class SpringMain {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc-test.xml");
		ServiceA svcA = context.getBean("svcA", ServiceA.class);
		svcA.doWork();
	}
}

保持不变,在Eclipse直接运行,得到结果:
自动扫描验证.png
很不幸,出现了异常。

仔细分析一下异常,提示说“No bean named ‘svcA’ available”,就是找不到id为svcA的Bean。有两种解决方案:

  • ServiceA类的注解添加Bean的id:@Service("svcA")
  • getBean方法使用默认的id:context.getBean("serviceA", ServiceA.class);

所以,自动扫描的注解也可以指定Bean的id,如果不指定,就使用Spring IoC的默认规则,即将类名的第一个字母变为小写(不过,似乎对于UUID这样的连续多个首字母大写的类名,会有一些问题,以后再讨论)。

大家可以尝试修改并运行一下。

其他注解

@Contorller

@Contorller注解与@Service@Repository注解类似,不过它的语义是控制层(也可以称为展示层)的Bean。

@Configuration

@Configuration注解实际上是为Spring IoC容器提供配置元数据的第三种方式,即基于Java的方式。

Spring IoC容器也会为该注解所修饰的类生成Bean,显然它的语义是配置层的Bean。

@Component

@Component实际上是@Service@Repository@Contorller@Configuration这几个注解的元注解,关于元注解,以后再讨论。

就是说,@Service等注解的定义需要由@Component来修饰。

实际上,Spring IoC容器也会为该注解所修饰的类生成Bean,不过,它的语义没有那些注解那么明确,仅仅表明是一个组件Bean而已。

总结

所有这些标记和注解都还有很多属性可以配置,比如组件扫描的过滤器和命名生成器等,大部分情况下,使用Spring IoC容器的默认规则即可,这些内容以后再讨论。

最核心的内容就是:

  • <component-scan>标记启用自动扫描和自动装配,实际上,有一个对应的注解@ComponentScan也是相同的作用,只不过它用在基于Java的配置中,而不是在XML中。
  • @Component@Service@Repository@Controller@Configuration等注解告诉Spring IoC容器要为这些注解所修饰的类在运行时生成Bean。
  • 自动扫描生成Bean的id默认是将类名首字母变为小写转化而来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值