In the previous article, we completed the loading object defined by Bean. This time, we completed the scope to obtain the value value, write the metadata and set the BeanName
scope system
Define scope source data class ScopeMetadata
/** * Define scope source data class */ public class ScopeMetadata { //Define the default values for the scope private String scopeName = BeanDefinition.SCOPE_SINGLETON; public String getScopeName() { return scopeName; } public void setScopeName(String scopeName) { this.scopeName = scopeName; } }
Define ScopeMetadata metadata injection interface ScopeMetadataResolver
/** *ScopeMetadata Metadata injection interface */ public interface ScopeMetadataResolver { ScopeMetadata resolverScopeMetadata(BeanDefinition beanDefinition); }
Define ScopeMetadata metadata injection concrete class AnnotationScopeMetadataResolver
/** * Implement scope metadata and define specific classes */ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver { private Class<? extends Annotation> scopeType = Scope.class; @Override public ScopeMetadata resolverScopeMetadata(BeanDefinition beanDefinition) { ScopeMetadata scopeMetadata = new ScopeMetadata(); // Gets the Class object processed by the current beanDefinition Class<?> beanClass = beanDefinition.getbeanClass(); // Judge whether there is @ ZXScopez annotation on the class object if (beanClass.isAnnotationPresent(scopeType)) { // Get ZXScope annotation object Scope annotation = ((Scope) beanClass.getAnnotation(scopeType)); // Get the value of the primary key setting String value = annotation.value(); if (!"".equals(value)) { scopeMetadata.setScopeName(value); } } return scopeMetadata; } }
Because the first doscan generates BeanDefinition objects, BeanDefinition is used here to judge
Test successful
Next, write the BeanName
Sort out the structure. In fact, there is also an AnnotationAttributes class in the source code, which is inherited from linkhasmap < string, Object >. Here we use reflection, so we don't operate like this.
Create BeanName interface
/** * Generate BeanName interface */ public interface BeanNameGenerator { String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry); }
AnnotationBeanNameGenerator concrete beanname implementation class
public class AnnotationBeanNameGenerator implements BeanNameGenerator { public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator(); @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { if (definition instanceof AnnotatedBeanDefinition){ AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) definition; //Get the Bean return value String beanName = determineBeanNameFromAnnotation(annotatedBeanDefinition); if (beanName.equals("")) { beanName = getDefultBeanName(definition); } System.out.println("Compont Return value:"+beanName); } ; return beanName; } //Get the annotation return value private String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedBeanDefinition) { //Get annotation metadata information AnnotationMetadata annotationMetadata = annotatedBeanDefinition.getAnnotationMetadata(); //Get the annotation return value String componentValue = annotationMetadata.getComponentValue(); return componentValue; } //Change uppercase to lowercase private String getDefultBeanName(BeanDefinition definition) { String getbeanClassName = definition.getbeanClassName(); char[] chars = getbeanClassName.toCharArray(); char aChar = chars[0]; if(aChar>='A'&&aChar<='Z'){ chars[0]+=32; } return new String(chars); } public AnnotationBeanNameGenerator(){ }; }
Here, a method getComponentValue is added to the metadata class to get the annotation Value
@Override public String getComponentValue() { String value = ""; if (resource.getClassLoader().isAnnotationPresent(Component.class)) { value= resource.getClassLoader().getAnnotation(Component.class).value(); } return value; }
Test success: user defines it for himself, and others are generated automatically
There is a problem here. I suddenly understand why the source code does not need to annotate objects, because the source code is a general method, which is through intercepting annotation Tostring(), write the template and copy the key code below
When outputting this code in the SimpleAnnotationMetadata class, you need to judge the price type
//@org.example.context.stereotype.Component(value=user) resource.getClassLoader().getAnnotations()[0].toString()
Write linkmap < string, Object > object in the format of Kev=vlaue, value=beanname
// Parse the current annotation object // @org.example.context.stereotype.Component(value=user) // The value=dao content obtained by intercepting the string String annotationString = annotation.toString(); int startIndex = annotationString.lastIndexOf("(") + 1; int endIndex = annotationString.lastIndexOf(")"); annotationString = annotationString.substring(startIndex, endIndex); String[] kv = annotationString.split("="); // Determine whether to set the value attribute if (kv.length > 1) { this.putIfAbsent(kv[0], kv[1]); } else { this.putIfAbsent(kv[0],EMPTY_STRING); }
Call:
// Get value as the value of the key, that is, the other name of the Bean, beanName String beanName = (String) AnnotationAttributes.get("value"); //Output return value
We use this method to get the following Lazy
public class AnalysisAnnocation extends LinkedHashMap<String,Object> { private Annotation annotation; private Class<? extends Annotation> annotationType; private static final String EMPTY_STRING = ""; public AnalysisAnnocation(){ } //Injection annotation public AnalysisAnnocation(BeanDefinition beanDefinition,Class<? extends Annotation> clazz){ if (beanDefinition.getbeanClass().isAnnotationPresent(clazz)) { this.annotation = beanDefinition.getbeanClass().getAnnotation(clazz); this.annotationType = annotation.annotationType(); } } public AnalysisAnnocation attributeFor() { attributeForMap(annotation); return this; } //Parse annotation tostring(); private void attributeForMap(Annotation annotation) { // Parse the current annotation object // @org.example.context.stereotype.Component(value=user) // The value=dao content obtained by intercepting the string //The Value here is not set well, because there may be cases where the Lazy object does not exist, so a default Value is set String string="(value='')"; if (annotation!=null) { string = annotation.toString(); } String annotationString =string ; int startIndex = annotationString.lastIndexOf("(") + 1; int endIndex = annotationString.lastIndexOf(")"); annotationString = annotationString.substring(startIndex, endIndex); String[] kv = annotationString.split("="); // Determine whether to set the value attribute if (kv.length > 1) { this.putIfAbsent(kv[0], kv[1]); } else { this.putIfAbsent(kv[0],EMPTY_STRING); } } }
Test successful
The next step is to verify whether there are beans in the factory. It has been parsed before, and it will be parsed again here
The factory and return factory object methods are constructed in the GenericApplicationContext constructor, the verification method is provided in the interface, implemented in the abstract class, the return factory object method is called, and the verification method is called
code
AbstractApplicationContext class
/** * Abstract classes implement interfaces, and concrete classes inherit abstractions */ public abstract class AbstractApplicationContext implements FuChaShengConfigurationApplicationContext { @Override public void refresh() { } //Verification method @Override public boolean containsBeanDefinition(String beanName) { return getBeanFactory().containsBeanDefinition(beanName); } //Call return factory method public abstract ConfigurableListableBeanFactory getBeanFactory(); }
GenericApplicationContext class
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { DefaultListableBeanFactory beanFactory ; public GenericApplicationContext(){ beanFactory = new DefaultListableBeanFactory(); } //Return to factory method @Override public ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory; } /** * Complete the core method of Bean definition * @param beanName * @param beanDefinition */ @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { this.beanFactory.registerBeanDefinition(beanName,beanDefinition); } @Override public String getId() { return null; } @Override public FuChaShengApplicationContext getParent() { return null; } @Override public void setId(String id) { } @Override public void setParent(AppletContext parent) { } @Override public Object getBean(String beanName) { return null; } }
BeanDefinitionRegistryBean defines the registration interface
/** * Bean Define registration interface */ public interface BeanDefinitionRegistry { void registerBeanDefinition(String beanName, BeanDefinition beanDefinition); boolean containsBeanDefinition(String beanName); }
Test it's OK
Look at the source code and turn around to BeanDefinitionHolder and BeanDefinitionRegistry interface object injection. If you don't know why, just build one according to the source code
BeanDefinitionReaderUtils helps inject classes
public class BeanDefinitionReaderUtils { public static void registryBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry) { // Get beanName and BeanDefinition String beanName = beanDefinitionHolder.getBeanName(); BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition(); registry.registerBeanDefinition(beanName, beanDefinition); } }
Call and judge methods
if (!checkCandidate(beanName)){ BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanName, beanDefinition); list.add(beanDefinitionHolder); // Register to IOC container registryBeanDefinition(beanDefinitionHolder, this.registry); //Injection plant this.registry.registerBeanDefinition(beanName,beanDefinition); } // Register to IOC container private void registryBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registryBeanDefinition(beanDefinitionHolder, registry); } /** * Check whether it has been registered in IOC * @param beanName * @return */ private boolean checkCandidate(String beanName) { return this.registry.containsBeanDefinition(beanName); }
summary
This article mainly simulates the scope system and Lazy's annotation acquisition process, improves the system and successfully injects it into the container. The middle structure hierarchy is not a copy, but the wonderful use of the later interface is becoming more and more wonderful. It feels ordinary when written. For example, judging that there is a Bean in the map is very good, and there is no taste when written. In addition, I directly use the reflection to obtain the scope, because I didn't want to understand why I should parse it at the beginning? Later, in the second Lazy, I found that the wonderful functions can be reused. Therefore, I simulated a supplement in the second Lazy. Anyway, there are many small surprises in the spring source code that need to be studied and studied again and again.
Baidu cloud: https://pan.baidu.com/s/1NBWus1v-CEJZu2NHsya2oA
Password: mdm6