[Spring]Annotation-based container configuration_AnotationBasis_02

本文深入解析Spring框架中关键注解的使用方法与应用场景,包括@Component、@Configuration、@Bean等,探讨它们之间的区别及如何利用这些注解进行依赖注入。

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

@Component @Repository @Service @Controller

本质上以上四类没有区别,但是在你定义应用分层的时候 aop的时候 这些不同语义的注解 就有不同意义,未来Spring是否会给予这些语义注解特殊的意义还并不清楚


在配置java类里面注解@ComponentScan(basePackages = "com.domain")的情况下,会自动扫描com.domain包里的所有类,扫描里面带有@Componet,@Repository,@Service..等等注解的类

该句等同于在xml配置文件里面加入了

<context:component-scan base-package="com.javaconfig.domain"/> 

同时@ComponentScan可以在加载包的时候,排除掉一些类,或者包含某些类

@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))

表示:扫描org.example包下所有带有@Component衍生的各种语义注解,同时包含该包下的匹配 .*Stub.*Repository类型的(正则匹配),排除扫描Repository.class

base-package的配置,从表面意思来看这是个“基本包”,表示下面的过滤路径是基于这个包的

更多过滤方式参考spring-reference


@Component

扫描一个类注册一个bean

@Component
public class Football {
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "football";
	}
}
这就注册了一个名为football的bean 命名规则为首字母小写,如果起始的两个字母都是大写,则不小写首字母。

@Component
public class XYclass {

}
注册了一个XYclass的bean
XYclass xyz = ctx.getBean("XYclass",XYclass.class);
获得该bean



@Bean

以类似工厂的方式产生bean,注意@Bean所在类必须要被spring所扫描到

Tool1:

public class Hammer implements Tool {
	public void doWork() {
		System.out.println("using hammer to smash something");
	}
}
Tool2:

public class Scissors implements Tool{
	public void doWork() {
		System.out.println("using scissors to cut something");
	}
}

ToolBox:

public class ToolBox {
	private Tool[] tools;

	public ToolBox(Tool t1, Tool t2) {
		tools = new Tool[] { t1, t2 };
	}

	public Tool[] getTools() {
		return tools;
	}

	public void setTools(Tool[] tools) {
		this.tools = tools;
	}

}



BeanFactory:
@Component
public class ToolFactory {

	@Bean
	@Qualifier("t1")
	public Tool hammer() {
		return new Hammer();
	}

	@Bean
	@Qualifier("t2")
	public Tool scissors() {
		return new Scissors();
	}

	@Bean
	public ToolBox toolBox(@Qualifier("t1") Tool t1, @Qualifier("t2") Tool t2,
			@Value("this is just tool box") String description) {
		System.out.println(description);
		return new ToolBox(t1, t2);
	}
}

Unit Test:

	@Test
	public void beanTest() {
		Tool t1 = ctx.getBean("hammer",Tool.class);
		Tool t2 = ctx.getBean("scissors",Tool.class);
		t1.doWork();
		t2.doWork();
		ToolBox tb = ctx.getBean("toolBox",ToolBox.class);
		
	}

@Bean产生的bean命名方式 就是方法名字 同时@Bean也会按照类型注入参数


@Configuration 和 @Component 的区别 

@Configuration也是从@Component 衍生出来的注解,但是@Component 相比@Configuration不同点在于,@Component 并没有通过CGLIB 增强调用所注册bean的内部方法和fields调用的。还有@Configuration内的@bean注解的方法 不能为final,因为这需要被CGLIB所重写。


@Component @Repository @Service @Controller等注解 也提供了 生成bean非默认名称方式命名

@Service("myMovieLister")
public class SimpleMovieLister { // ...
}
比如该bean名称就会是myMovielister



@Scope

提供了在注册bean的时候申明该bean的lifecycle

@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}


@Configuration

是类级注册bean的注解,该类自身被注册为bean,并且其内的@Bean注解的方法 都会注册为bean。并且顾名思义,这就是一个配置类。

@Configuration
public class AppConfig {
	
	@Bean
	public Foo foo(Bar bar){
		return new Foo(bar);
	}
	
	@Bean
	public Bar bar(){
		return new Bar();
	}
}

这里申明的都是单例实类

Unit Test:

@Test
	public void beanTest2() {
		Foo foo = ctx.getBean("foo", Foo.class);
		Foo foo2 = ctx.getBean("foo", Foo.class);
		Bar bar = ctx.getBean("bar", Bar.class);
		Bar bar2 = ctx.getBean("bar", Bar.class);
		assertEquals(foo, foo2);
		assertEquals(bar, bar2);
		assertEquals(foo.getBar(), foo2.getBar());
	}

测试通过


@Import

导入配置类

@Configuration @Import(ConfigA.class) public class ConfigB {
@Bean
public B b() { return new B();
} }



@ImportResource

导入配置文件

@ImportResource(value = "TestCase_01.xml")



@Condtional

@Conditional注解主要用在以下位置:
类级别可以放在注标识有@Component(包含@Configuration)的类上
作为一个meta-annotation,组成自定义注解
方法级别可以放在标识由@Bean的方法上
如果一个@Configuration的类标记了@Conditional,所有标识了@Bean的方法和@Import注解导入的相关类将遵从这些条件。

简单的说就是根据某些情况选择合适的类进行注册

首先需要编写条件,条件类必须实现Condtion接口的matches方法

判断是否为Mac os

public class MacOsCondition implements Condition{
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		
		return context.getEnvironment().getProperty("os.name").contains("Mac OS X");
	}
}
判断是否为Linux

public class LinuxCondition implements Condition{
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		return context.getEnvironment().getProperty("os.name").contains("Linux");
	}
}

注册bean的时候或者注册整个类的时候用上

	@Bean(name = "systemService")
	@Conditional(LinuxCondition.class)
	public SystemService linuxService() {
		return new LinuxService();
	}

	@Bean(name = "systemService")
	@Conditional(MacOsCondition.class)
	public SystemService macService() {
		return new MacOsService();
	}

根据操作系统不同选择不同的服务

Unit Test:

@Test
	public void conditionTest() {
		SystemService service = ctx.getBean("systemService",SystemService.class);
		service.service();
	}



@Profile

如果在开发时进行一些数据库测试,希望链接到一个测试的数据库,以避免对开发数据库的影响。

该注解提供了灵活的在多个副本之间切换的方法

注册了一个用于开发测试的mockDBService和一个release的MysqlDBService

	@Bean(name = "dbService")
	@Profile("dev")
	public DBService mockDBService(){
		return new MockDBService();
	}
	
	@Bean(name = "dbService")
	@Profile("rc")
	public DBService MysqlDBService(){
		return new MysqlDBService();
	}
	

在进行单元测试的时候

使用@ActiveProfiles(value = "dev")激活所要使用的副本

Unit Test:

@Test
	public void profileTest() {
		DBService dbService = ctx.getBean(DBService.class);
		System.out.println(dbService.count("select * from users"));
	}

也可以使用java激活方式

ctx.getEnvironment().setActiveProfiles("dev");
		ctx.register(AppConfig.class);
		ctx.refresh();




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值