talk is cheap,show me the code!!!
实战
Person.java
@Component("person")
public class Person {
public void say(){
System.out.println("hello world");
}
}
AbstractService.java
public abstract class AbstractService {
@Resource
protected Person person;
public abstract void service();
}
ConcreteService.java
@Service
public class ConcreteService extends AbstractService{
@Override
public void service() {
person.say();
}
}
ProxyConfig
@Configuration
@ComponentScan("org.example.bean")
public class ProxyConfig {
}
App.java
public class App
{
public static void main( String[] args ) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProxyConfig.class);
AbstractService service = context.getBean(AbstractService.class);
service.service();
context.close();
}
}
result:
原理
在spring执行依赖注入的时候会执行 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean(该流程是在doCreateBean方法里)
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties
在postProcessProperties通过findResourceMetadata收集需要注入的字段、方法
然后通过inject进行注入
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
{
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try
{
metadata.inject(bean, beanName, pvs);
}
catch(Throwable ex)
{
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#findResourceMetadata
findResourceMetadata先从缓存获取。如果没有就执行buildResourceMetadata构建需要注入的字段、方法
private InjectionMetadata findResourceMetadata(String beanName, Class <? > clazz, @Nullable PropertyValues pvs)
{
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if(InjectionMetadata.needsRefresh(metadata, clazz))
{
synchronized(this.injectionMetadataCache)
{
metadata = this.injectionMetadataCache.get(cacheKey);
if(InjectionMetadata.needsRefresh(metadata, clazz))
{
if(metadata != null)
{
metadata.clear(pvs);
}
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#buildResourceMetadata
buildResourceMetadata会解析当前类的字段、方法看看有没有符合要求的。
然后会解析父类的。最后几行!!!!
private InjectionMetadata buildResourceMetadata(Class <? > clazz)
{
if(!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes))
{
return InjectionMetadata.EMPTY;
}
List < InjectionMetadata.InjectedElement > elements = new ArrayList < > ();
Class <? > targetClass = clazz;
do {
final List < InjectionMetadata.InjectedElement > currElements = new ArrayList < > ();
ReflectionUtils.doWithLocalFields(targetClass, field - >
{
if(ejbClass != null && field.isAnnotationPresent(ejbClass))
{
if(Modifier.isStatic(field.getModifiers()))
{
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
else if(field.isAnnotationPresent(Resource.class))
{
if(Modifier.isStatic(field.getModifiers()))
{
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if(!this.ignoredResourceTypes.contains(field.getType().getName()))
{
currElements.add(new ResourceElement(field, field, null));
}
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method - >
{
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if(!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod))
{
return;
}
if(method.equals(ClassUtils.getMostSpecificMethod(method, clazz)))
{
if(ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass))
{
if(Modifier.isStatic(method.getModifiers()))
{
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if(method.getParameterCount() != 1)
{
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if(bridgedMethod.isAnnotationPresent(Resource.class))
{
if(Modifier.isStatic(method.getModifiers()))
{
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class <? > [] paramTypes = method.getParameterTypes();
if(paramTypes.length != 1)
{
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if(!this.ignoredResourceTypes.contains(paramTypes[0].getName()))
{
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
Resource、Autowired都会解析父类