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();
    }

}

最后运行,

控制台输出:测试成功

时间: 2024-10-12 03:55:38

springMvc的注解注入方式的相关文章

注解学习(模仿springMvc的注解注入方式)

最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识.由于本人也是抱着学习的态度来阅读源码,若文章在表述和代码方面如有不妥之处,欢迎批评指正.留下你的脚印,欢迎评论!希望能互相学习. 1,首先定义三个常用的注解Service,Autowired,Contrller:(主要的解释都在代码中有,在这里就不多陈述) Service: package com.lishun.Annotation; import

spring 四种依赖注入方式以及注解注入方式

平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化, 而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员, 而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. spring有多种依赖注

利用反射实现简单的Spring注解注入实例

一时兴起,这两天看了看Spring的源代码,就想写一个简单的Spring利用注解注入!!Spring的注解注入方式给了我们很方便的好处!大家应该都了解Spring的注入原理,在这里写下一个非常简单的使用注解来注入的实例,做个小小的笔记! 要使用注解,那就绝对和反射离不开.摘抄一段 Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性.例如,使用它能获得 Java 类中各成员的名称并显示出来. J

SpringMVC的注解方式

mvc-servlet.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springf

Springmvc注解注入的简单demo

今天看了注解注入觉得确实简化了xml配置,一般情况下Spring容器要成功启动的三大要件分别是:Bean定义信息,Bean实现类,以及spring本身.如果采取基于XML的配置,Bean信息和Bean实现类本身是分离的,而采用注解基于注解配置的方式,Bean定义信息通过在Bean实现类上标注注解实现,这种方式确实简化了xml配置,但是是不是某种程度增加了耦合? 常用的注解有Autowired.Resource.Qualifier.Service.Controller.Repository.Com

一篇非常经典的springMVC注解实现方式详解

今天公司让搭建个springMVC的注解框架,研究了好半天,网络搜罗了半天,好不容易找到篇,拿来分享下: 原文出处:http://www.itxxz.com/a/kuangjia/2014/0531/4.html 大家好,我是IT学习者的螃蟹,前两天写了一个spring MVC的注解实例,目前看来下载使用的人数已有不少,使用过程中也有不少人对其中的配置存有一些不解和疑问,在这里螃蟹就那个实例中的spring配置详细说明一下,算作是对spring注解模式的一次全方位解析.         在实例中

【SpringMVC学习03】SpringMVC中注解和非注解方式下的映射器和适配器总结

从上一篇的springmvc入门中已经看到,springmvc.xml中的配置了映射器和适配器,是使用非注解的方式来配置的,这是非注解方式的一种,这里再复习一下: 1. 非注解方式 1.1 处理器适配器 上一节中使用的处理器适配器是:org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.即: SimpleControllerHandlerAdapter适配器能执行实现了Controller接口的Handler,所以我

我爱Java系列之---【SpringBoot中常用的注解和两种注入方式】

@EnableConfigurationProperties(DataSourceProperties.class) 来声明要使用DataSourceProperties 这个类并初始化该类对象,该类不用放在IOC容器中,可以通过该注解直接使用. [email protected]:一般写在类上边,通过该注解将当前类初始化到Spring的IOC容器中,其他类若想调用,直接用@Autowired去容器中拿. [email protected]: 一般写在类上边,标明该类是一个配置类,被注解的类内部

spring四种依赖注入方式 (set,构造器,工厂,注解 )

平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中.依赖注入的另一种说法是"控制反转",通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做. spring有多种