1. @Value和@propertysource
平时我们使用spring时,会有一些类的属性随环境的值不同,一般我们会将其写入properties文件中。这个配置文件我们可以通过@propertysource注解加载到系统中,再利用@Value注入到类属性中。
@Configuration
@PropertySource(value="classpath:/jdbc.properties")
public class Cap8MainConfig {
@Value(${jdbc.driver})
private String driver;
@Value(${jdbc.url})
private String url;
@Value(${jdbc.username})
private String username;
@Value(${jdbc.password})
private String password;
}
2. @Autowired
@Autowired默认是按照类型进行注入的,那如果存在两个同类型的对象,但bean的id不同。@Autowired会加载哪一个呢。
第一个对象:
@Repository
public class TestDao {
private String flag = "1";
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
@Override
public String toString() {
return "TestDao [flag=" + flag + "]";
}
}
第二个对象:
@Configuration
public class Cap9MainConfig {
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
}
@Service
public class TestService {
//这时候按照类型注入,有两个对象
@Autowired
private TestDao testDao;
public void println(){
System.out.println(testDao);
}
}
先说下答案再分析:如果同类型的对象存在两个,会按照名称注入,也就是选择第一个对象。我们来分析下源码证明下,Autowired对应的后置处理器为Autowiredannotationbeanpostprocessor。处理字段属性注入的是其内部类AutowiredFieldElement的inject方法。
(1)inject方法
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//解析属性核心方法
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
(2)beanFactory.resolveDependency调用的是DefaultListableBeanFactory.resolveDependency方法,该方法核心又调用了doResolveDependency方法。
(3)doResolveDependency方法
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//这里为空
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
//这里为空
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
//这里为空
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//找寻匹配的所有类,如果有Qualifier注解,这里会根据条件返回一个
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
//如果匹配的类有多个,这里就是我们前面谈论的,如果匹配的类型不止一个
if (matchingBeans.size() > 1) {
//这个方法就是判断选择哪个bean
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
(4)determineAutowireCandidate
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
//这里判断符合条件的类是否实现了@Primary注解
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
//这里是优先级判断,我们没判断
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// Fallback
//我们前面说的如果根据类型有多个的话,会再根据名称选择就在这里
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
//这里是判断bean的名称和属性注入的字段名是否相同
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
3.@Primary
上述的问题,如果有多个类型符合条件,又想匹配指定的类型可以利用@Primary注解。上面在源码分析到了。
@Primary
@Bean("testDao2")
public TestDao testDao(){
TestDao testDao = new TestDao();
testDao.setFlag("2");
return testDao;
}
4. @Qualifier
利用@Qualifier也可以实现注入指定的类。这个在上述源码中提到了。就在findAutowireCandidates这个方法。
(1)findAutowireCandidates方法
这个方法会调用本类的isAutowireCandidate方法
(2)isAutowireCandidate方法
protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
resolveBeanClass(mbd, beanDefinitionName);
if (mbd.isFactoryMethodUnique && mbd.factoryMethodToIntrospect == null) {
new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
}
//如果用了Qualifier注解,这里用的是QualifierAnnotationAutowireCandidateResolver
//没有Qualifier注解,这里用的是GenericTypeAwareAutowireCandidateResolver
return resolver.isAutowireCandidate(
new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
}
从方法调用顺序也可以看出,如果同时使用了@Qualifier和@Primary,会按照@Qualifier注解来执行。
5. @Resource
@Resource对应的后置处理器是CommonAnnotationBeanPostProcessor。可以选择根据name和type注入。
@Resource和Autowired区别:
@Resource和Autowired一样可以装配bean
@Resource缺点: 不能支持@Primary功能
不能支持@Autowired(required = false)的功能
5. @Inject
@Inject和Autowired一样可以装配bean, 并支持@Primary功能, 可用于非spring框架.
@Inject缺点: 但不能支持@Autowired(required = false)的功能,需要引入第三方包javax.inject