Spring对象的几种装配方式

1. 环境配置

1.1 使用Maven进行测试

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.0.8.RELEASE</version>
</dependency>
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>

2. Xml装配

2.1 新建aplicationContext.xml文件

<beans>
	<bean id="person" class="entity.Person">
		<property name="name" value="lisi"/>
		<property name="age" value="10"/>
	</bean>
	<bean id="constructorPerson" class="entity.Person">
		<constructor-arg name="name" value="zhangsan"/>
		<constructor-arg name="age" value="20"/>
	</bean>
</beans>

2.2 新建person对象

public class Person {
	private String name;
	private int age;
	//省略setter和getter+有参构造函数
}

2.3 新建测试类

public class PersonTest extends TestCase {

	@Test
	public void testBean() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		Person person = (Person) applicationContext.getBean("person");
		System.out.println(person);
	}

	@Test
	public void testPerson() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		String[] definitionNames = applicationContext.getBeanDefinitionNames();
		for (String name : definitionNames) {
			System.out.println(name);
		}
	}
}

2.4 测试结果:

Person(name=lisi, age=10)

person
constructorPerson

2.5 结果分析:

不管是使用property还是使用构造参数传入值,都可以进行对象的获取


3. 配置类

3.1 使用Java代码进行配置,需要用到的注解@Configuration
3.2 新建配置类:@Configuration表示这是一个注解@Bean表示这是一个需要装配的对象,具体表现为bean文件,可以参考使用xml进行配置中的第一个对象的装配

@Configuration
public class BeanConfiguration {
	@Bean
	public Person person() {
		return new Person("王五", 20);
	}
}

3.3 新建测试类:

public class BeanConfigurationTest extends TestCase {
	@Test
	public void testPerson() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfiguration.class);
		Person person = applicationContext.getBean(Person.class);
		System.out.println(person);
	}	
}

AnnotationConfigApplicationContext 表示使用注解的方式进行获取配置类,传入配置类作为参数,便获得了applicationContext对象,接着便可以使用该对象进行获得bean对象了。


4. Bean扫描的方式

在xml中可以配置某个包下面的类可以进行全部扫描,避免了每个类都需要配置的烦恼

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

这样便可以直接扫描该包下所有配置了注解的类
常用的注解类有以下几种:
@Controller:一般用于Controller层
@Service:一般用于Sercice层
@Reposity:一般用于Dao层
@Component:一般不建议使用,该注解无具体描述,只表示这是一个注解
可以使用Java的方式来进行配置

4.1 方式一

@ComponentScans(value = {
		@ComponentScan(value = "com.entity"),
}
@Configuration
public class BeanScanConfiguration {

}

使用@ComponentScans的目的是,该注解下,可以配置多个@CompoentScan注解,便于扩展,当然jdk1.8以后,可以直接使用多个同名注解,也不会报错了。
上面的注解意思是扫描com.entity包下的所有类

4.2 方式二

@ComponentScan(basePackageClasses = {Person.class, PersonDao.class, PersonService.class, PersonController.class, CarController.class})

作用:直接给定需要装配的类,会自动进行装配,不建议使用,了解即可

4.3 方式三

@ComponentScan(excludeFilters = {
	@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
})

作用:进行一些类的排除,FilterType一共有五种,分别是:
FilterType.ANNOTATION:排除或添加指定的注解
FilterType.ASSIGNABLE_TYPE:排除或添加指定的类型
FilterType.ASPECTJ:按照切面进行排除或添加
FilterType.REGEX:按照正则表达式排除或添加
FilterType.CUSTOM:自定义排除或添加,需要实现TypeFilter接口
介绍自定义排除:

public class MyTypeFilter implements TypeFilter {
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
		//获得元数据信息
		AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
		annotationMetadata.getAnnotationTypes().forEach(System.out::println);
		ClassMetadata classMetadata = metadataReader.getClassMetadata();
		System.out.println(classMetadata.getClassName());
		Resource resource = metadataReader.getResource();
		System.out.println(resource.getURI());
		if (classMetadata.getClassName().contains("red")) {
			return true;
		}
		return false;
	}
}

使用方法:

@ComponentScan(includeFilters = {
	@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
})

同理,其他的需要添加进来的类,也可以按照相同的方法进行添加,即便刚排除了,然后又添加了,那依然算最后添加进来的,注解为@includeFilters


5. 使用Import进行导入

@Import(value = {Red.class, Green.class, PersonDao.class})
@Configuration
public class BeanImportConfiguration {

}

作用:导入对应的实体类

5.1 自定义import导入

可以实现ImportSelectorImportBeanDefinitionRegistrar接口

5.1.1 实现ImportSelector的方式

public class MyImportSelector implements ImportSelector {

	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		importingClassMetadata.getAnnotationTypes().forEach(System.out::println);
		return new String[]{"entity.Yellow"};
	}
}

返回一个String数组,数组里面保存的是需要装配的对象的包+对象名

5.1.2 实现ImportBeanDefinitionRegistrar的方式

与上述方法不同的是,Register可以自己注册bean,上面那个需要等待别人装配,只是返回需要装配的对象的位置而已。

public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {

	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition("entity.Red")) {
			BeanDefinition beanDefinition = new RootBeanDefinition(Black.class);
			registry.registerBeanDefinition("black", beanDefinition);

		}
	}
}

可以注册别名,如果不注册,默认为对象名

6. 使用条件注解@Conditional进行装配

注册之前,需要实现Condition接口

public class WindowCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment environment = context.getEnvironment();
		String property = environment.getProperty("os.name");
		if (property.contains("Windows")) {
			return true;
		}
		return false;
	}
}
public class LinuxCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		Environment environment = context.getEnvironment();
		String property = environment.getProperty("os.name");
		if (property.contains("Linux")) {
			return true;
		}
		return false;
	}
}

上面注册了两个条件,如果当前为Window环境,对应的返回true,表示可装配,否则返回false,表示不可装配
具体的配置类:

@Configuration
public class BeanConditionConfiguration {

	@Conditional(WindowCondition.class)
	@Bean
	public Person createPerson() {
		return new Person("Bill", 20);
	}

	@Conditional(LinuxCondition.class)
	@Bean
	public Person person() {
		return new Person("Linus", 30);
	}
}

在测试类中,只输出了一个bean对象


7. 使用BeanFactory进行装配

使用需要实现BeanFactory接口
具体的实现如图

public class ColorFactoryBean implements FactoryBean {

	@Override
	public boolean isSingleton() {
	//是否单例
		return true;
	}

	@Override
	public Object getObject() throws Exception {
	//需要返回的对象
		return new Blue();
	}

	@Override
	public Class<?> getObjectType() {
	//需要返回的对象
		return Blue.class;
	}
}

配置类

@Configuration
public class BeanFactoryConfiguration {
	@Bean
	public ColorFactoryBean createColor() {
		return new ColorFactoryBean();
	}
}

测试结果:虽然装配的是ColorFactoryBean,但是得到的却是Color,如果需要得到工厂类对象,需要获取的时候这样进行获取

Object bean = applicationContext.getBean("&createColor");

这样获得的对象就是工厂对象本身,而不是装配的对象

猜你喜欢

转载自blog.csdn.net/qq_32409957/article/details/85934431