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

王朝学院·作者佚名  2016-08-27  
宽屏版  字体: 小 | 中 | 大 | 超大  

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

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

Service:

packagecom.lishun.Annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.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@interfaceService {/*@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。

* 方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。

* 可以通过default来声明参数的默认值。*/String value()default"this is service annotation";

}

Autowired:

packagecom.lishun.Annotation;importjava.lang.annotation.Documented;importjava.lang.annotation.ElementType;importjava.lang.annotation.Inherited;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)public@interfaceAutowired {publicString value()default"no description";

}

Contrller:

packagecom.lishun.Annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)public@interfaceContrller {

String value()default"this is contrller annotation";

}

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

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

packagecom.lishun.factory;importjava.util.HashMap;importjava.util.Map;/*** Description:存放所有bean的数据池

*@authorlishun

*@since2015-09-10*/publicclassBeanFactory {privatestaticMap<String, Object> map =newHashMap<String, Object>();publicstaticvoidaddBean(String beanName, Object bean) {

map.put(beanName, bean);

}publicstaticObject getBean(String beanName)throwsException {

Object o=map.get(beanName);if(o !=null) {returno;

}else{thrownewException("未注入的类型:" +beanName);

}

}publicstaticBoolean containsBean(String beanName){returnmap.containsKey(beanName);

}

}

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

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

AnnotationDriven:

packagecom.lishun.utils;importjava.lang.annotation.Annotation;importjava.lang.reflect.Field;importjava.util.List;importcom.lishun.Annotation.Autowired;importcom.lishun.Annotation.Contrller;importcom.lishun.Annotation.Service;importcom.lishun.factory.BeanFactory;/*** Description:注入驱动类,所有的注解注入都在这里实现(这里只实现了通过类型来注入值,其他方式没实现,其实代码都是差不多了,有兴趣的可以自行脑补)

*@authorlishun

**/publicclassAnnotationDriven {publicstaticvoidannotationDriven(String packName)throwsException {//注入Service和ContrllerList<Class<?>> classSaveServicePaths =PackUtils

.getClassListByAnnotation(packName, Service.class);

List<Class<?>> classSaveContrllerPaths =PackUtils

.getClassListByAnnotation(packName, Contrller.class);

saveBean(classSaveServicePaths);

saveBean(classSaveContrllerPaths);//注入AutowiredList<Class<?>> classInjectPaths =PackUtils.getClassListByAnnotation(

packName, Autowired.class);

inject(classInjectPaths);

}privatestaticvoidsaveBean(List<Class<?>>classSavePaths)throwsInstantiationException, 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();

}

}

}privatestaticvoidinject(List<Class<?>> classInjectPaths)throwsException {

Object o=null;for(Class<?>classInjectPath : classInjectPaths) {

Class c=Class.forName(classInjectPath.getName());//判断存放bean的池中是否存在该beanif(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(annotationinstanceofAutowired) {

Class classField=field.getType();

Object clazz=BeanFactory

.getBean(classField.getName());

field.set(o, clazz);

BeanFactory.addBean(classInjectPath.getName(), o);

}

}

}

}

}

}

PackUtils:

packagecom.lishun.utils;importjava.io.File;importjava.io.FileFilter;importjava.lang.annotation.Annotation;importjava.lang.reflect.Field;importjava.net.JarURLConnection;importjava.net.URL;importjava.util.ArrayList;importjava.util.Enumeration;importjava.util.List;importjava.util.jar.JarEntry;importjava.util.jar.JarFile;/*** Description:扫描指定包工具类的注解

*@authorlishun

*@since2015-09-10*/publicclassPackUtils {publicstaticList<Class<?>> getClassList(String packageName,booleanisRecursive) {

List<Class<?>> classList =newArrayList<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);

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

}returnclassList;

}//获取指定包名下的所有类(可根据注解进行过滤)publicstaticList<Class<?>> getClassListByAnnotation(String packageName, Class<?extendsAnnotation>annotationClass) {

List<Class<?>> classList =newArrayList<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);

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

}returnclassList;

}privatestaticvoidaddClass(List<Class<?>> classList, String packagePath, String packageName,booleanisRecursive) {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();

}

}privatestaticFile[] getClassFiles(String packagePath) {returnnewFile(packagePath).listFiles(newFileFilter() {

@Overridepublicbooleanaccept(File file) {return(file.isFile() && file.getName().endsWith(".class")) ||file.isDirectory();

}

});

}privatestaticString getClassName(String packageName, String fileName) {

String className= fileName.substring(0, fileName.lastIndexOf("."));if(!packageName.equals("")) {

className= packageName + "." +className;

}returnclassName;

}privatestaticString getSubPackagePath(String packagePath, String filePath) {

String subPackagePath=filePath;if(!packagePath.equals("")) {

subPackagePath= packagePath + "/" +subPackagePath;

}returnsubPackagePath;

}privatestaticString getSubPackageName(String packageName, String filePath) {

String subPackageName=filePath;if(!packageName.equals("")) {

subPackageName= packageName + "." +subPackageName;

}returnsubPackageName;

}privatestaticvoidaddClassByAnnotation(List<Class<?>> classList, String packagePath, String packageName, Class<?extendsAnnotation>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

packagecom.lishun.Dao;importcom.lishun.Annotation.Service;

@ServicepublicclassUserDao {publicvoidrun(){

System.out.println("测试成功");

}

}

Service:

packagecom.lishun.Service;importcom.lishun.Annotation.Autowired;importcom.lishun.Annotation.Service;importcom.lishun.Dao.UserDao;

@ServicepublicclassUserService {

@AutowiredpublicUserDao userDao;publicvoidrun(){

userDao.run();

}

}

Controller:

packagecom.lishun.controller;importcom.lishun.Annotation.Autowired;importcom.lishun.Annotation.Contrller;importcom.lishun.Service.UserService;

@ContrllerpublicclassUserContrller {

@AutowiredpublicUserService userService;publicvoidlogin(){

userService.run();

}

}

测试入口

packagecom.lishun.t;importjava.lang.annotation.Annotation;importjava.lang.reflect.Field;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.util.Arrays;importjava.util.List;importorg.junit.Test;importcom.lishun.Annotation.Autowired;importcom.lishun.Annotation.Contrller;importcom.lishun.Annotation.Service;importcom.lishun.Dao.UserDao;importcom.lishun.Service.UserService;importcom.lishun.controller.UserContrller;importcom.lishun.factory.BeanFactory;importcom.lishun.utils.AnnotationDriven;importcom.lishun.utils.PackUtils;publicclasstest {

@Testpublicvoidmain()throwsException {//启动时根据需要扫描的包名,来注入含有注解的类的字段值AnnotationDriven.annotationDriven("com.lishun");//这里相当于web的访问一次controller的一次请求UserContrller user =(UserContrller) BeanFactory

.getBean("com.lishun.controller.UserContrller");

user.login();

}

}

最后运行,

控制台输出:测试成功

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
© 2005- 王朝网络 版权所有