博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
注解学习(模仿springMvc的注解注入方式)
阅读量:6921 次
发布时间:2019-06-27

本文共 14445 字,大约阅读时间需要 48 分钟。

最近在看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 等。 * */@Documentedpublic @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
map = new HashMap
(); 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
> classSaveServicePaths = PackUtils .getClassListByAnnotation(packName, Service.class); List
> classSaveContrllerPaths = PackUtils .getClassListByAnnotation(packName, Contrller.class); saveBean(classSaveServicePaths); saveBean(classSaveContrllerPaths); //注入Autowired List
> classInjectPaths = PackUtils.getClassListByAnnotation( packName, Autowired.class); inject(classInjectPaths); } private static void saveBean(List
> 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
> 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
> getClassList(String packageName, boolean isRecursive) { List
> classList = new ArrayList
>(); try { Enumeration
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
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
> getClassListByAnnotation(String packageName, Class
annotationClass) { List
> classList = new ArrayList
>(); try { Enumeration
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
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
> 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
> classList, String packagePath, String packageName, Class
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;@Servicepublic 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;@Servicepublic 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;@Contrllerpublic 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();    }}

最后运行,

控制台输出:测试成功

由于本人水平有限,若文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!希望能互相学习。需要源码的留下邮箱

 

转载于:https://www.cnblogs.com/lishun1005/p/4800936.html

你可能感兴趣的文章
Iwpriv工作流程及常用命令使用
查看>>
《FLUENT 14.0超级学习手册》——第1章 流体力学与计算流体力学基础1.1 流体力学基础...
查看>>
Last_IO_Error: error connecting to master 'tl@192.168.199.151:3306'
查看>>
Objective-C中的老板是这样发通知的(Notification)
查看>>
资源分享计划第四期 0518
查看>>
如何最骚气得在linux下聊qq(mojoqq)
查看>>
docker mysql 容器时区不对
查看>>
MDK使用技巧及bug解决
查看>>
移除button在IE67下的黑边
查看>>
FusionShpere 简介
查看>>
java正则判断URL
查看>>
爬取百度贴吧的一些图片,使用request、re、urllib模块
查看>>
Python 斐波那契数列优化
查看>>
Servlet 笔记
查看>>
2015-1-22(mac升级yosemite之后xampp中mysql不能启动的问题解决)
查看>>
2013年6月工作小结-- 再论需求与设计,别总去×××拉松
查看>>
【源码】c#编写的安卓客户端与Windows服务器程序进行网络通信
查看>>
ClistCtrl列表控件添加复选框功能
查看>>
Storm 集群异常的解决
查看>>
7_12_2013 B: A simple problem
查看>>