zoukankan      html  css  js  c++  java
  • springMvc的注解注入方式

    springMvc的注解注入方式

    最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识。由于本人也是抱着学习的态度来阅读源码,若文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!希望能互相学习。

     

    1,首先定义三个常用的注解Service,Autowired,Contrller;(主要的解释都在代码中有,在这里就不多陈述)

     

    Service:

     

    复制代码
    package com.lishun.Annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /*Description:
     * @Target:指定注解的使用范围(指的是,在哪些类型可以使用该注解:Service注解只能在类,接口(包括注解类型)或enum等使用)
     * 可选值:
     * 可选的值在枚举类 ElemenetType 中,包括: 
              ElemenetType.CONSTRUCTOR 构造器声明 
              ElemenetType.FIELD 域声明(包括 enum 实例) 
              ElemenetType.LOCAL_VARIABLE 局部变量声明
              ElemenetType.ANNOTATION_TYPE 作用于注解量声明
              ElemenetType.METHOD 方法声明
              ElemenetType.PACKAGE 包声明 
              ElemenetType.PARAMETER 参数声明 
              ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 
    
     * */
    
    @Target(ElementType.TYPE)
    /*Description:
     * @Retention :表示在什么级别保存该注解信息
     * 可选的参数值在枚举类型 RetentionPolicy 中,包括: 
              RetentionPolicy.SOURCE 注解将被编译器丢弃 
              RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 
              RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 
     * */
    @Retention(RetentionPolicy.RUNTIME)
    
    /*@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
     * 在doc文档中的内容会因为此注解的信息内容不同而不同。相当与@see,@param 等。
     * */
    @Documented
    
    
    public @interface Service {
        /* @interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。
         * 方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。
         * 可以通过default来声明参数的默认值。
        */
        String value() default "this is service annotation";
    }
    复制代码

     

     

    Autowired:

     

    复制代码
    package com.lishun.Annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD,ElementType.FIELD})  
    @Retention(RetentionPolicy.RUNTIME)  
    public @interface Autowired {
          public String value() default "no description";  
    }
    复制代码

     

    Contrller:

     

    复制代码
    package com.lishun.Annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Contrller {
        String value() default "this is contrller annotation";
    }
    复制代码

     

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     

    2:javaBean数据池-BeanFactory:主要存放含有注解的类;

     

    复制代码
    package com.lishun.factory;
    
    import java.util.HashMap;
    import java.util.Map;
    /**
     * Description:存放所有bean的数据池 
     * @author lishun
     * @since 2015-09-10
     */
    public class BeanFactory {
        private static Map<String, Object> map = new HashMap<String, Object>();
    
        public static void addBean(String beanName, Object bean) {
            map.put(beanName, bean);
        }
    
        public static Object getBean(String beanName) throws Exception {
            Object o = map.get(beanName);
            if (o != null) {
                return o;
            } else {
                throw new Exception("未注入的类型:" + beanName);
            }
        }
        public static Boolean containsBean(String beanName){
            return map.containsKey(beanName);
        }
    }
    复制代码

     

     

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     

    3:编写处理注解的核心代码(这里涉及的主要知识是反射,如果反射知识不够熟练的话建议先学习反射方面的知识),主要涉及的两个类是注解驱动(AnnotationDriven)和注解扫描类(PackUtils-这个类主要的是扫描包名下所有的类(如com.lishun,就是扫描该包下所有的类),代码主要是来自网络)

     

    AnnotationDriven:

     

    复制代码
    package com.lishun.utils;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.util.List;
    
    import com.lishun.Annotation.Autowired;
    import com.lishun.Annotation.Contrller;
    import com.lishun.Annotation.Service;
    import com.lishun.factory.BeanFactory;
    
    /**
     * Description:注入驱动类,所有的注解注入都在这里实现(这里只实现了通过类型来注入值,其他方式没实现,其实代码都是差不多了,有兴趣的可以自行脑补)
     * @author lishun
     *
     */
    public class AnnotationDriven {
        public static void annotationDriven(String packName) throws Exception {
            //注入Service和Contrller
            List<Class<?>> classSaveServicePaths = PackUtils
                    .getClassListByAnnotation(packName, Service.class);
            List<Class<?>> classSaveContrllerPaths = PackUtils
                    .getClassListByAnnotation(packName, Contrller.class);
            saveBean(classSaveServicePaths);
            saveBean(classSaveContrllerPaths);
            //注入Autowired
            List<Class<?>> classInjectPaths = PackUtils.getClassListByAnnotation(
                    packName, Autowired.class);
            inject(classInjectPaths);
        }
    
        private static void saveBean(List<Class<?>> classSavePaths)
                throws InstantiationException, IllegalAccessException {
            for (Class<?> classPath : classSavePaths) {
                try {
                    Class c = Class.forName(classPath.getName());
                    Object o = c.newInstance();
                    //扫描的到的含有注解的类实例化后保存在池中
                    BeanFactory.addBean(classPath.getName(), o);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private static void inject(List<Class<?>> classInjectPaths) throws Exception {
            Object o = null;
            for (Class<?> classInjectPath : classInjectPaths) {
    
                Class c = Class.forName(classInjectPath.getName());
                //判断存放bean的池中是否存在该bean
                if (BeanFactory.containsBean(classInjectPath.getName())) {
                    o = BeanFactory.getBean(classInjectPath.getName());
                } else {
                    o = c.newInstance();
                }
                Field[] fields = c.getDeclaredFields();
                for (Field field : fields) {
                    Annotation[] annotations = field.getAnnotations();
                    for (Annotation annotation : annotations) {
                        // 判断是否是通过类型注解注入
                        if (annotation instanceof Autowired) {
                            Class classField = field.getType();
                            Object clazz = BeanFactory
                                    .getBean(classField.getName());
                            field.set(o, clazz);
                            BeanFactory.addBean(classInjectPath.getName(), o);
    
                        }
                    }
                }
    
            }
        }
    }
    复制代码

     

    PackUtils:

     

    复制代码
    package com.lishun.utils;
    import java.io.File;
    import java.io.FileFilter;
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.net.JarURLConnection;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.List;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;
    /**
     * Description:扫描指定包工具类的注解
     * @author lishun
     * @since 2015-09-10
     */
    public class PackUtils {
        public static List<Class<?>> getClassList(String packageName, boolean isRecursive) {
            List<Class<?>> classList = new ArrayList<Class<?>>();
            try {
                Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\.", "/"));
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    if (url != null) {
                        String protocol = url.getProtocol();
                        if (protocol.equals("file")) {
                            String packagePath = url.getPath();
                            addClass(classList, packagePath, packageName, isRecursive);
                        } else if (protocol.equals("jar")) {
                            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                            JarFile jarFile = jarURLConnection.getJarFile();
                            Enumeration<JarEntry> jarEntries = jarFile.entries();
                            while (jarEntries.hasMoreElements()) {
                                JarEntry jarEntry = jarEntries.nextElement();
                                String jarEntryName = jarEntry.getName();
                                if (jarEntryName.endsWith(".class")) {
                                    String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                    if (isRecursive || className.substring(0, className.lastIndexOf(".")).equals(packageName)) {
                                        classList.add(Class.forName(className));
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return classList;
        }
    
        // 获取指定包名下的所有类(可根据注解进行过滤)
        public static List<Class<?>> getClassListByAnnotation(String packageName, Class<? extends Annotation> annotationClass) {
            List<Class<?>> classList = new ArrayList<Class<?>>();
            try {
                Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\.", "/"));
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    if (url != null) {
                        String protocol = url.getProtocol();
                        if (protocol.equals("file")) {
                            String packagePath = url.getPath();
                            addClassByAnnotation(classList, packagePath, packageName, annotationClass);
                        } else if (protocol.equals("jar")) {
                            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                            JarFile jarFile = jarURLConnection.getJarFile();
                            Enumeration<JarEntry> jarEntries = jarFile.entries();
                            while (jarEntries.hasMoreElements()) {
                                JarEntry jarEntry = jarEntries.nextElement();
                                String jarEntryName = jarEntry.getName();
                                if (jarEntryName.endsWith(".class")) {
                                    String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                    Class<?> cls = Class.forName(className);
                                    if (cls.isAnnotationPresent(annotationClass)) {
                                        classList.add(cls);
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return classList;
        }
    
        private static void addClass(List<Class<?>> classList, String packagePath, String packageName, boolean isRecursive) {
            try {
                File[] files = getClassFiles(packagePath);
                if (files != null) {
                    for (File file : files) {
                        String fileName = file.getName();
                        if (file.isFile()) {
                            String className = getClassName(packageName, fileName);
                            classList.add(Class.forName(className));
                        } else {
                            if (isRecursive) {
                                String subPackagePath = getSubPackagePath(packagePath, fileName);
                                String subPackageName = getSubPackageName(packageName, fileName);
                                addClass(classList, subPackagePath, subPackageName, isRecursive);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static File[] getClassFiles(String packagePath) {
            return new File(packagePath).listFiles(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
                }
            });
        }
    
        private static String getClassName(String packageName, String fileName) {
            String className = fileName.substring(0, fileName.lastIndexOf("."));
            if (!packageName.equals("")) {
                className = packageName + "." + className;
            }
            return className;
        }
    
        private static String getSubPackagePath(String packagePath, String filePath) {
            String subPackagePath = filePath;
            if (!packagePath.equals("")) {
                subPackagePath = packagePath + "/" + subPackagePath;
            }
            return subPackagePath;
        }
    
        private static String getSubPackageName(String packageName, String filePath) {
            String subPackageName = filePath;
            if (!packageName.equals("")) {
                subPackageName = packageName + "." + subPackageName;
            }
            return subPackageName;
        }
    
        private static void addClassByAnnotation(List<Class<?>> classList, String packagePath, String packageName, Class<? extends Annotation> annotationClass) {
            try {
                File[] files = getClassFiles(packagePath);
                if (files != null) {
                    for (File file : files) {
                        String fileName = file.getName();
                        if (file.isFile()) {
                            String className = getClassName(packageName, fileName);
                            Class<?> cls = Class.forName(className);
                            if (cls.isAnnotationPresent(annotationClass)) {
                                classList.add(cls);
                            }
                            Field[] fields=cls.getFields();
                            for (Field field : fields) {
                                if(field.isAnnotationPresent(annotationClass)){
                                     classList.add(cls);
                                }
                            }
                        } else {
                            String subPackagePath = getSubPackagePath(packagePath, fileName);
                            String subPackageName = getSubPackageName(packageName, fileName);
                            addClassByAnnotation(classList, subPackagePath, subPackageName, annotationClass);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

     

     

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     

    4 最后编写平时使用的设计模式来测试注解(Dao,Service,Contrller)【这里主要是为测试注解的注入,所以没有使用实际的使用数据库数据,侧重点不在这里】

     

    Dao

     

    复制代码
    package com.lishun.Dao;
    
    import com.lishun.Annotation.Service;
    
    @Service
    public class UserDao {
        public void run(){
            System.out.println("测试成功");
        }
    }
    复制代码

     

    Service:

     

    复制代码
    package com.lishun.Service;
    
    import com.lishun.Annotation.Autowired;
    import com.lishun.Annotation.Service;
    import com.lishun.Dao.UserDao;
    @Service
    public class UserService {
        @Autowired
        public UserDao userDao;
    
        public void run(){
             userDao.run();
        }
    
    }
    复制代码

     

    Controller:

     

    复制代码
    package com.lishun.controller;
    
    import com.lishun.Annotation.Autowired;
    import com.lishun.Annotation.Contrller;
    import com.lishun.Service.UserService;
    @Contrller
    public class UserContrller {
        @Autowired
        public  UserService userService;
        public void login(){
            userService.run();
        }
    }
    复制代码

     

    测试入口

     

    复制代码
    package com.lishun.t;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.Arrays;
    import java.util.List;
    
    import org.junit.Test;
    
    import com.lishun.Annotation.Autowired;
    import com.lishun.Annotation.Contrller;
    import com.lishun.Annotation.Service;
    import com.lishun.Dao.UserDao;
    import com.lishun.Service.UserService;
    import com.lishun.controller.UserContrller;
    import com.lishun.factory.BeanFactory;
    import com.lishun.utils.AnnotationDriven;
    import com.lishun.utils.PackUtils;
    
    public class test {
    
        @Test
        public void main() throws Exception {
            //启动时根据需要扫描的包名,来注入含有注解的类的字段值
            AnnotationDriven.annotationDriven("com.lishun");
            //这里相当于web的访问一次controller的一次请求
            UserContrller user = (UserContrller) BeanFactory
                    .getBean("com.lishun.controller.UserContrller");
            user.login();
        }
    
    }
    复制代码

     

    最后运行,

     

    控制台输出:测试成功

  • 相关阅读:
    hihocoder 1049 后序遍历
    hihocoder 1310 岛屿
    Leetcode 63. Unique Paths II
    Leetcode 62. Unique Paths
    Leetcode 70. Climbing Stairs
    poj 3544 Journey with Pigs
    Leetcode 338. Counting Bits
    Leetcode 136. Single Number
    Leetcode 342. Power of Four
    Leetcode 299. Bulls and Cows
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4803847.html
Copyright © 2011-2022 走看看