Simulate and implement annotation Assembly in Spring, spring Annotation

Source: Internet
Author: User

Simulate and implement annotation Assembly in Spring, spring Annotation

Original article, address for http://www.cnblogs.com/fengzheng/p/5037359.html

In Spring, bean configuration in the XML file is the core configuration file for implementing Spring IOC. in earlier versions of Spring, dependencies between objects can only be configured based on XML configuration files. Annotations have appeared after Spring 2.5. The method of combining annotations with XML simplifies the XML configuration complexity.

Pure XML configuration in old versions for IOC

Configure the following in the configuration file:

<bean id="userDao" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl">   <property name="userDao" ref="userDao"></property> </bean>

The implementation of UserServiceImpl is as follows:

public class UserServiceImpl implements UserService {    public UserDao getUserDao() {        return userDao;    }    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    private UserDao userDao;    public User getUserById(int id){        return userDao.getUserById(id);    }    public int getUserCount(){        return userDao.getUserCount();    }} 

<Property name = "userDao" ref = "userDao"> </property> This line of configuration specifies the bean userDao in the UserServiceImpl class, in this way, the method used to call userDao in the UserServiceImpl class is actually to call com. springapp. mvc. dao. userDao method.

Implementation with annotations

The configuration file is simplified as follows:

<bean id="userDao" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl"> </bean>

The implementation of UserServiceImpl is as follows:

public class UserServiceImpl implements UserService {    @Autowired    private UserDao userDao;    public User getUserById(int id){        return userDao.getUserById(id);    }    public int getUserCount(){        return userDao.getUserCount();    }}

Use the @ Autowired annotation to configure <property name = "userDao" ref = "userDao"> </property> in xml, so as to implement automatic injection. @ Autowired the automatic injection rule is byType, which means that the annotation field type matches the bean type configured in xml, that is, the userDao type in UserServiceImpl class is UserDao, when matching, all beans are searched for beans of the same type as UserDao.

If two beans of the same type exist, the Second Matching Rule ByName is enabled, that is, the bean with the same id is matched according to the field name. The following XML Configuration:

<bean id="userDao1" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userDao2" class="com.springapp.mvc.dao.UserDao"></bean><bean id="userService" class="com.springapp.mvc.service.impl.UserServiceImpl"></bean>

In the UserServiceImpl class, you should use the following method for automatic injection:

@Autowiredprivate UserDao userDao1;@Autowiredprivate UserDao userDao2;

This seems to be not very flexible, and it looks a little uncomfortable. Is there a way to specify the bean to be matched? Yes, yes. You can use this method by combining @ Autowired and @ Qualifier. The parameter followed by @ Qualifier is the bean Name:

@Autowired@Qualifier("userDao1")private UserDao userDao;

There are also more common methods, @ Resource:

@Resource(name = "userDao1")private UserDao userDao;

For more information about IOC annotations, see this article.

The usage of annotations in Spring is over. Next we will practice a simple class to simulate the principle of using annotations in Spring to implement IOC.

Implementation principle of Spring IOC

1. First, Spring collects all bean instances according to the bean configuration file;

2. Spring scans the packages to be injected according to the context: component-scan in the configuration file (all classes to be injected in the recursive package );

3. When the class to be injected is scanned, determine whether there are specific annotations (for example, @ Autowired and @ Resource). If yes, perform Step 1 and inject the annotation;

4. injection: Use reflection based on Annotation types or parameters to set bean instances for the annotated fields or attributes.

The above is my personal understanding, and may be somewhat different from the real implementation of Spring.

Simulate Injection Using annotations

Here we need to define an annotation similar to @ Resource named @ MyAutowired. The definition is as follows:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.FIELD})@Documentedpublic @interface MyAutowired {public String name() default "";public String value() default "";}

Define the configuration file:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns:context="http://www.springframework.org/schema/context"><context:component-scan id="test" class="fengzheng.Test"/><bean id="tomoto" class="fengzheng.Tomoto"></bean></beans>

Bean and bean in Spring have the same definition, while context: component-scan defines the base-package attribute in Spring, and then scans all classes in this package based on this attribute, this is a demonstration and is also defined as a class. The class will be injected according to this class attribute.

Tomoto bean definition in the configuration file:

package fengzheng;public class Tomoto {public void SayHello(){System.out.println("hello I'm tomoto");}}

Fengzheng. Test class definition in the configuration file, which is the class to be injected:

package fengzheng;import fengzheng.fzAnnotation.MyAutowired;public class Test {@MyAutowired(name = "tomoto")private Tomoto tomoto; public void Say(){tomoto.SayHello();}}

Core annotation analysis and injection class:

Import java. lang. reflect. field; import java.net. URL; import java. util. arrayList; import java. util. hashMap; import java. util. iterator; import java. util. list; import java. util. map; import org. dom4j. document; import org. dom4j. element; import org. dom4j. io. SAXReader; import fengzheng. fzAnnotation. myAutowired; import java. util. stream. *; public class FzClassPathXMLApplication {// private List defined by bean in the xml configuration file <BeanDef Ine> beanList = new ArrayList <BeanDefine> (); // stores the ing between bean instances and bean IDs so that you can find the corresponding instance Map based on the annotation name <String, object> beanInstanceList = new HashMap <String, Object> (); // The set of scan class definitions in the xml configuration file scan one or more packages in the Spring framework <ScanDefine> scanList = new ArrayList <ScanDefine> (); // store the scanned Object collection Map <String, Object> annotationInstanceList = new HashMap <String, Object> (); public FzClassPathXMLApplication (String xmlName) {Read Xml (xmlName); // instantiate all defined beanBeanInstance (); // instantiate all the class ScanClassInstance () to be injected; // start to inject InjectAnnotation () according to the annotation ();} /*** read the bean collection from the configuration file and the collection of classes to be injected * @ param xmlFileName */public void ReadXml (String xmlFileName) {URL xmlPath = this. getClass (). getClassLoader (). getResource (xmlFileName); System. out. println (xmlPath); SAXReader reader = new SAXReader (); try {Document dom = reader. read (xmlPath); Element root = dom. get RootElement (); List <Element> iters = root. elements (); Stream <Element> beans = iters. stream (). filter (bean-> bean. getName (). equals ("bean"); Iterator <Element> iterBeans = beans. iterator (); while (iterBeans. hasNext () {Element bean = iterBeans. next (); String id = bean. attributeValue ("id"); String clsName = bean. attributeValue ("class"); // System. out. println ("id:" + id + "\ nclass:" + clsName); BeanDefine bd = New BeanDefine (); bd. setId (id); bd. setClsName (clsName); beanList. add (bd);} Stream <Element> scanClasses = iters. stream (). filter (scan-> scan. getName (). equals ("component-scan"); // iters. stream (). forEach (scan-> System. out. println (scan. getName (); Iterator <Element> iterScans = scanClasses. iterator (); while (iterScans. hasNext () {Element scan = iterScans. next (); String id = scan. attributeValue ("id"); String ClsName = scan. attributeValue ("class"); ScanDefine sd = new ScanDefine (); sd. setId (id); sd. setClassName (clsName); scanList. add (sd);} System. out. println ("scanList. size (): "+ scanList. size ();} catch (Exception e) {e. printStackTrace () ;}/ *** collect bean instance */private void BeanInstance () {for (BeanDefine bd: beanList) {try {Object beanInstance = Class. forName (bd. getClsName ()). newInstance (); System. out. println (be AnInstance. getClass (). getName (); beanInstanceList. put (bd. getId (), beanInstance);} catch (Exception e) {e. printStackTrace () ;}}/ *** collects instances of the classes to be injected scanned */private void ScanClassInstance () {for (ScanDefine sd: scanList) {try {Object scanInstance = Class. forName (sd. getClassName ()). newInstance (); System. out. println (scanInstance. getClass (). getName (); annotationInstanceList. put (sd. getId (), scanInstance);} catch (Exception e) {e. printStackTrace () ;}}/ *** cyclically traverse the class to be injected */public void InjectAnnotation () {Iterator <Map. entry <String, Object> iters = annotationInstanceList. entrySet (). iterator (); while (iters. hasNext () {Map. entry <String, Object> iter = iters. next (); Object scanInstance = iter. getValue (); InjectField (scanInstance) ;}/ *** injection: inject the annotation in the class to MyAutowired into the bean instance * @ param injectClass */private void InjectF Ield (Object injectClass) {try {Field [] fields = injectClass. getClass (). getDeclaredFields (); for (Field field: fields) {if (Field! = Null & field. isAnnotationPresent (MyAutowired. class) {System. out. println (field. getName (); MyAutowired myAutowired = field. getAnnotation (MyAutowired. class); String beanName = myAutowired. name (); Object value = null; if (beanName! = Null &&! BeanName. equals ("") {value = beanInstanceList. get (beanName);} else {Class <?> FType = field. getType (); for (String key: beanInstanceList. keySet () {if (fType. isAssignableFrom (beanInstanceList. get (key ). getClass () {value = beanInstanceList. get (key); break ;}} field. setAccessible (true); field. set (injectClass, value) ;}} catch (Exception e) {e. printStackTrace () ;}} public Object getScan (String scanName) {return this. annotationInstanceList. get (scanName );}}

 

Two entity classes used in the annotation processing class:

package fengzheng.simpleSpring;public class BeanDefine {private String id;private String clsName;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClsName() {return clsName;}public void setClsName(String clsName) {this.clsName = clsName;}}package fengzheng.simpleSpring;public class ScanDefine {public String id;public String className;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}}

Explanation of the program logic:

1. first, read the configuration file beans using the ReadXml () method. xml, find the bean node and context: component-scan node, instantiate the bean node as BeanDefine, add the beanList set, and instantiate the component-scan node as ScanDefine, add the scanList set;

2. By using the BeanInstance () method, all beans in the configuration file are instantiated and stored in the beanInstanceList set of Map;

3. Use the ScanClassInstance () method to instantiate the component-scan node (that is, the class to be injected) in the configuration file and go to the annotationInstanceList of the Map set everywhere;

4. Use the InjectAnnotation () method to traverse the annotationInstanceList set and assign values to the fields annotated by @ MyAutowired (that is, the corresponding bean instance)

The call implementation is as follows:

FzClassPathXMLApplication ctx = new FzClassPathXMLApplication("beans.xml");Test test =(Test) ctx.getScan("test");test.Say();

Output result:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.