最近在看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();
} }

最后运行,

控制台输出:测试成功

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

注解学习(模仿springMvc的注解注入方式)的更多相关文章

  1. SpringBoot入门一:基础知识(环境搭建、注解说明、创建对象方法、注入方式、集成jsp/Thymeleaf、logback日志、全局热部署、文件上传/下载、拦截器、自动配置原理等)

    SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,SpringBoot致力于在蓬勃发 ...

  2. java注解学习(1)注解的作用和三个常用java内置注解

    今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...

  3. Spring学习笔记(3)——Bean的注入方式

    依赖注入 依赖注入支持属性注入.构造函数注入.工厂注入. 属性注入: 属性注入即通过setXxx()方法注入Bean的属性值或依赖对象 属性注入要求Bean提供一个默认的构造函数(无参构造函数),并为 ...

  4. springMVC的bean注入方式

    POJO是多例模式,并不是单例模式. servlet是单例的,同一个实例可以同时有多个用户访问 用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存:用多例,是为了防止并发问题:单 ...

  5. SpringMVC 常用注解 详解

    SpringMVC 常用注解 详解 SpringMVC 常用注解 1.@RequestMapping                                      路径映射 2.@Requ ...

  6. springMVC基于注解的控制器

    springMVC基于注解的控制器 springMVC基于注解的控制器的优点有两个: 1.控制器可以处理多个动作,这就允许将相关操作写在一个类中. 2.控制器的请求映射不需要存储在配置文件中.使用re ...

  7. springMvc的注解注入方式

    springMvc的注解注入方式 最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识.由于本人也是抱着 ...

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

    从上一篇的springmvc入门中已经看到,springmvc.xml中的配置了映射器和适配器,是使用非注解的方式来配置的,这是非注解方式的一种,这里再复习一下: 1. 非注解方式 1.1 处理器适配 ...

  9. [原创]java WEB学习笔记103:Spring学习---Spring Bean配置:基于注解的方式(基于注解配置bean,基于注解来装配bean的属性)

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

随机推荐

  1. Struts 2.3.24源码解析+Struts2拦截参数,处理请求,返回到前台过程详析

    Struts2官网:http://struts.apache.org/ 目前最新版本:Struts 2.3.24 Struts1已经完全被淘汰了,而Struts2是借鉴了webwork的设计理念而设计 ...

  2. Linux命令速查手册,超详细Linux命令教程

    一.常用命令速查 ls cd pwd cat more less tail head cp scp mv mkdir rmdir touch rm ps kill top free clear tre ...

  3. 设计模式之 面向对象的养猪厂的故事,C#演示(一)

    对于设计模式, 从本质上说, 其最大的用途就是适应需求的变化. 因为有了设计模式,我们可以在设计阶段就为未来可能发生的变化留下足够的空间. 我们通过一个建造现代化养猪场的故事, 来讨论一下设计模式与需 ...

  4. C#调用C和C++函数的一点区别

    最近做U800电话的二次开发,需要调用厂商的C函数库来打电话,后来想加入通话录音功能,但发现程序默认生产的WAV文件过大,又找了个WAV转MP3的C++函数库程序,出了点问题.下面是转MP3的程序接口 ...

  5. ASP.NET 多语言的实现(后台消息+前台消息+页面自动绑定)

    一 前言 界面支持多种语言,在使用ASP.NET自带的多语言方案时遇到下列问题: 在做管理类的功能时,有添加.修改和查看页面,需要支持多语言的控件基本相同,但要维护多处,产生冗余(ASP.NET有共享 ...

  6. 充满想象力的 JavaScript 物理和重力实验

    在这个列表中挑选了9个物理和重力实验,用来展示 Javascript 的强大.几年前,所有这些实验都必须使用 Java 或 Flash 才能做.在下面这些惊人的例子中,就个人而言,我比较喜欢仿真布料的 ...

  7. Sublime Text 3汉化中文版

    Sublime Text 3汉化中文版是Sublime Text2的升级版.Sublime Text 是一款流行的文本编辑器软件,有点类似于TextMate,跨平台,可运行在Linux,Windows ...

  8. Moqui简介

    Moqui简介 Moqui是一个生态系统理念,是需要一系列的能够用于构建企业自动化办公的开源软件的组合,如:eCommerce, ERP, CRM, SCM, MRP, EAM, POS, 等等. 架 ...

  9. web页面直接跳转至其他页面

    <script type="text/javascript">window.location.herf="../../XXXXX.aspx";< ...

  10. AE常见接口之间的关系(较笼统)+arcgis常见概念

    常见的接口有如下关系 IworkspaceFactory-------------->IworkSpace------------------>IfeatureWorkSpace ---- ...