What is IOC?

SpringIOC stands for inversion of control. Objects that are traditionally created and managed by ourselves are now in the hands of Spring, which is responsible for controlling the life cycle of objects and their relationships.

implementation

When using the spring into the bean, we have two ways, one is XML, is a kind of annotation, now we implement annotation ways to implement a simple ioc, here we need to implement custom annotations, about custom annotations can reference another article, shows the directory structure, to look at the implementation which annotations.

@Component, which sets the bean ID with value.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {
     String value() default "";
}

Copy the code

At sign Controller, at sign Service

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}

Copy the code

@scope sets the Scope of the bean, singleton, Prototype, Request, Session, global Session.

@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "";
}

Copy the code

@value, which injects a specific Value into the property.

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, Elementtype.annotation_type}) @retention (retentionPolicy.runtime) public @value {// Define Value attribute String Value (); }Copy the code

Then there are the core classes. The first map contains the class definition object. The first map contains the class definition object. The first map contains the class definition object.

Private map <String,Class<? >> beanDefinationFactory = new ConcurrentHashMap<>(); Private Map<String,Object> singletonBeanFactory = new ConcurrentHashMap<>();Copy the code

Define a constructor that scans the package against the path passed in at initialization time.

/ / definition and construct the incoming to scan the package path of public AnnotationConfigApplicationContext (String packageName) {/ / scan specified package scanPKG (packageName); }Copy the code

Implement a package scan method that stores all classes annotated with @Controller, @Component, and @Service into a map with keys and class definition objects.

@param packageName/private void scanPKG(final String packageName) {// Use final Modifier to prevent incoming arguments from being modified calls // first convert the incoming package path to a directory structure. Replace with/String pkgDir = packageName. ReplaceAll ("\\.","/"); String URL = getClass().getClassLoader().getResource(pkgDir).getPath(); // try {url = urldecoder. decode(url, "utF-8 "); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } // create a File object based on path File File = new File(url); // Get all files ending in. Class in this path //listFiles Returns the absolute paths of all files and directories in a directory. List Returns the names of all files and directories in a directory File.listfiles (new FileFilter() {// FileNameFilter @override public Boolean Accept (file file) {// Obtain file name String fileNmae = file.getName(); If (file.isdirectory ()){scanPKG(packageName + "." + fileNmae); }else{class if (filenmae.endswith (".class")){return true; } } return false; }}); For (file f:files) {String fileName = f.get_name (); FileName = filename.subString (0, filename.lastIndexof (".")); PkgCls = packageName + "." + fileName; Try {// Create object Class<? > clazz = Class.forName(pkgCls); / / determine whether need to inject the bean's comments if (clazz. IsAnnotationPresent (Controller. Class) | | clazz. IsAnnotationPresent (Component. Class) | | clazz.isAnnotationPresent(Service.class)){ String key = getKey(clazz); If (key == null){// Use lowercase as the map key. Key = String.valueof (filename.charat (0)).tolowerCase () + filename.substring (1); } beanDefinationFactory.put(key, clazz); } } catch (ClassNotFoundException e) { e.printStackTrace(); }}}Copy the code

Implement the getKey method to determine whether the value of the annotation is the default value. If not, return the value. If it is the default value, use lowercase as the key of the class name.

private String getKey(Class<? > clazz) { String key = null; / / determine whether this class have the Component annotation the if (clazz. IsAnnotationPresent (Component. Class)) {/ / if you have this annotation is to obtain the value value, if you have a custom value value, set this value to the key, Otherwise, use the default key if (! ".equals(clazz.getDeclaredAnnotation(Component.class).value())){ key = clazz.getDeclaredAnnotation(Component.class).value(); }} the if (clazz isAnnotationPresent (Controller. Class)) {/ / if you have this annotation is to obtain the value value, if you have a custom value value, set this value to the key, or use the default key if (!" ".equals(clazz.getDeclaredAnnotation(Controller.class).value())){ key = clazz.getDeclaredAnnotation(Controller.class).value(); }} the if (clazz isAnnotationPresent (Service. Class)) {/ / if you have this annotation is to obtain the value value, if you have a custom value value, set this value to the key, or use the default key if (!" ".equals(clazz.getDeclaredAnnotation(Service.class).value())){ key = clazz.getDeclaredAnnotation(Service.class).value();  } } return key; }Copy the code

The beans that should be implemented are already stored in the map. The next step is getBean, which gets the specific object via beanId.

Public Object getBean(String beanId){// getBean(String beanId){// getBean(String beanId){// getBean(String beanId) Class<? > clazz = beanDefinationFactory.get(beanId); if (clazz == null){ throw new NoSuchBeanDefinitionException(beanId, "No matching bean found for bean name '" + beanId + "'! (Note: Qualifier matching not supported because given BeanFactory does not implement ConfigurableListableBeanFactory.)"); } String scope = null; // Check whether the class has the @scope annotation. To obtain the value of the inside the if (clazz isAnnotationPresent (Scope. The class)) {Scope = clazz. GetDeclaredAnnotation (Scope. The class). The value (); } if ("".equals(scope)){// If scope is empty, Singleton Prototype Request Session Global Session scope = "singleton"; If ("singleton".equals(scope)){if("singleton".equals(scope)){if("singleton".equals(scope)){ If (singletonBeanFactory.get(beanId) == null){Object instance = clazz.newinstance (); SetFiledValues (clazz, instance); singletonBeanFactory.put(beanId, instance); } return singletonBeanFactory.get(beanId); } if ("prototype".equals(scope)){ Object instance = clazz.newInstance(); setFiledValues(clazz, instance); return instance; } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } // Return null if an exception is encountered; }Copy the code

Implement the custom exception method used above

/ * * * custom exception Showed no current bean object * / public class NoSuchBeanDefinitionException extends RuntimeException {private String beanName; public NoSuchBeanDefinitionException(String beanName, String message){ super("No bean named '" + beanName + "' available: " + message); this.beanName = beanName; }}Copy the code

Implement the method setFiledValues() that assigns values to member attributes.

* @param Clazz class defines an object * @param obj specifies an instance object to which an assignment is to be made */ private void setFiledValues(Class<? > clazz, Object obj){// Get all attributes Field[] fields = clazz.getDeclaredFields(); For (Field Field :fields){field.setaccessible (true); for (Field Field :fields){field.setaccessible (true); Value. If (field. IsAnnotationPresent (class)) {/ / get annotations in the Value of the String Value = field. The getAnnotation (Value. The class). The Value (); String type = field.getType().getSimplename (); try{ if ("Integer".equals(type) || "int".equals(type)){ int intValue = Integer.valueOf(value); field.set(obj,intValue); }else if("String".equals(type)){ field.set(obj,value); } } catch (IllegalAccessException e) { e.printStackTrace(); }}}}Copy the code

Implement an overloaded method of getBean that returns the type of the class object passed in

/** * override method, * @param beanId * @param c * @param <T> * @return */ public <T> T getBean(String beanId, String beanId) Class<T> c){ return (T)getBean(beanId); }Copy the code

Destruction method, used to release resources

/ * * * destroy method Used to release resources * / public void the close () {beanDefinationFactory. The clear (); singletonBeanFactory.clear(); beanDefinationFactory = null; singletonBeanFactory = null; }Copy the code

So far, the basic realization of the annotation method to achieve IOC, write relatively simple, because the annotation is more detailed, so there is no too much explanation, but many of the judgment is not added, mainly for easy to understand, if there is anything wrong, please give more advice.