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

最后运行,
控制台输出:测试成功
springMvc的注解注入方式的更多相关文章
- 注解学习(模仿springMvc的注解注入方式)
最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识.由于本人也是抱着学习的态度来阅读源码,若文章在表述 ...
- spring 四种依赖注入方式以及注解注入方式
平常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程 ...
- springMVC 使用注解注入接口实现类
spring常用的注释: @Component:标准一个普通的spring Bean类. @Controller:标注一个控制器组件类. @Service:标注一个业务逻辑组件类. @Reposi ...
- SpringMVC常用注解,返回方式,路径匹配形式,验证
常用注解元素 @Controller 标注在Bean的类定义处 @RequestMapping 真正让Bean具备 Spring MVC Controller 功能的是 @RequestMapping ...
- springMVC的bean注入方式
POJO是多例模式,并不是单例模式. servlet是单例的,同一个实例可以同时有多个用户访问 用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存:用多例,是为了防止并发问题:单 ...
- Spring IOC 注入方式详解 附代码
引言 Spring框架作为优秀的开源框架之一,深受各大Java开发者的追捧,相信对于大家来说并不陌生,Spring之所以这么流行,少不了他的两大核心技术IOC和IOP.我们这里重点讲述Spring框架 ...
- SpringBoot入门一:基础知识(环境搭建、注解说明、创建对象方法、注入方式、集成jsp/Thymeleaf、logback日志、全局热部署、文件上传/下载、拦截器、自动配置原理等)
SpringBoot设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,SpringBoot致力于在蓬勃发 ...
- SpringMVC中注解和非注解方式下的映射器和适配器总结
1. 非注解方式 1.1 处理器适配器 上一节中使用的处理器适配器是:org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapte ...
- Spring学习笔记3——使用注解的方式完成注入对象中的效果
第一步:修改applicationContext.xml 添加<context:annotation-config/>表示告诉Spring要用注解的方式进行配置 <?xml vers ...
随机推荐
- Codeforces Round#309 C Kyoya and Colored Balls
给定一个k表示颜色的种类从1到k 然后接下来k行, 每行一个数字, 代表该颜色的球有多少个 这些球都放在一个包中,然后依次拿出. 要求颜色i的最后一个球, 必须要排在颜色i+1的最后一个球前面, ...
- BDB (Berkeley DB)简要数据库(转载)
使用最近DBD.然后搜了下相关资料,首先公布的是一门科学: 转会http://www.javaeye.com/topic/202990 DB综述DB最初开发的目的是以新的HASH訪问算法来取代旧的hs ...
- PageRank算法MapReduce实现
如果你现在需要计算网页的排名只有4一:数据如下面的: baidu 10.00 google,sina,nefu google 10.00 baidu sina 10.00 google nefu 10 ...
- ios在SQLite3基本操作
iOS关于sqlite3操作 iPhone中支持通过sqlite3来訪问iPhone本地的数据库. 详细用法例如以下 1:加入开发包libsqlite3.0.dylib 首先是设置项目文件.在项目中加 ...
- Google Maps Android API v2 (4)- 地图类型
地图类型 地图内的谷歌地图的Android API的种类有很多.地图的类型管辖地图的整体代表性.例如,地图集通常包含政治地图,专注于显示边界和道路地图,显示了一个城市或地区的所有道路. Android ...
- hive的非交互模式
在linux的终端运行:$HIVE_HOME/bin/hive 会进入交互模式: $HIVE_HOME/bin/hive -e或者-f 是非交互模式 1.非交互模式运行HQL语句 $HIVE_HOM ...
- [LeetCode]Word Ladder 最短距离字符串转换 (Dijkstra)
要求最短距离.采纳dijkstra查找节点之间的最短路径. 当心:假设是一个枚举字典22是否元素可以,如果转换,暂停. 提高:每串,带您历数它的字符值事件,对于的长度n一个字符串枚举n*26次要. 设 ...
- 区域及分离、Js压缩、css、jquery扩展
后台管理区域及分离.Js压缩.css.jquery扩展 本系列目录:ASP.NET MVC4入门到精通系列目录汇总 有好一段时间没更新博文了,最近在忙两件事:1.看书,学习中...2.为公司年会节目做 ...
- 移动web:翻页场景动画
在移动web,特别是在微信中,经常看到一种翻页动画效果,也称为场景动画. 一页一页的翻过,像在看书,每页的内容以各种"炫酷"的效果出现在你的眼里,配上一首动听的音乐,你有没有喜欢上 ...
- Oracle性能优化顺序表名称来选择最有效的学习笔记
选择最有效的顺序表名(只有有效的基于规则的优化) ORACLE分析器按照订单处理从右到左FROM在FROM子句中的表名,故FROM写在最后的表(基础表 driving table)将被最先处理. 在 ...