继续前面的章节,这里我介绍下注解,其实Java注解跟.NetCore的特性标签类似,下面我们通过代码来说明
Java自定义注解
首先我先说下Java注解需要使用的注解
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
Taget:指定注解在什么地方生效,作用于什么对象上,参数很多这里把源码拉出来了,每一个的意思就不过多介绍,一看就明白
public enum ElementType { /** 类、接口(包括注释类型)或枚举声明 */ TYPE, /** 字段声明(包括枚举常量) */ FIELD, /** 方法声明 */ METHOD, /** 形式参数声明 */ PARAMETER, /** 构造函数声明 */ CONSTRUCTOR, /** 局部变量声明 */ LOCAL_VARIABLE, /** 注释类型声明 */ ANNOTATION_TYPE, /** 程序包声明 */ PACKAGE, /** * 类型参数声明 * * @since 1.8 */ TYPE_PARAMETER, /** * 使用类型 * * @since 1.8 */ TYPE_USE }
public enum RetentionPolicy { /** 注解将被编译器丢弃 */ SOURCE, /** 注解将由编译器记录在类文件中,但在运行时不需要由VM保留。这是默认的行为。 */ CLASS, /** 注解将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射读取当前注解。*/ RUNTIME }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { /* 注解表明这个注解应该被 javadoc工具记录 */ }
下面就来模拟一个自定义的注解,同时简单并模拟MyBatis中的像如下写法,解析下面代码的实现原理
@Select("SELECT username,email,newname,nick_name FROM user_model") @Results({ @Result(property = "username", column = "username"), @Result(property = "email", column = "email"), @Result(property = "newname", column = "newname"), @Result(property = "nickName", column = "nick_name") }) List<UserModel> getAll();
这里定义一个自定义的注解接口 代码如下,注解要作用于方法上
Target(value = ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CustomSelect { String Sql() default ""; }
这一步也非常简单,定义一个操作接口,使用自定义的注解,添加好相关的Sql语句
public interface ReflectorDao { @CustomSelect(Sql = "select * from user_model where id=1") int InsertModel(); }
接下来就是怎么使用了,当然这里还是要用到反射 ,这里我添加了一个测试方法,里面模拟实现了一个JDBC的操作方法
@Test public void testReflectorDao() throws Exception { Class<?> c= ReflectorDao.class; Method method=c.getMethod("InsertModel"); CustomSelect customSelect=method.getAnnotation(CustomSelect.class); String strsql= customSelect.Sql(); System.out.print(strsql+"\r\n"); //调用JDBC完成操作 JDBCHelper.ExcuteQuery(strsql); }
这里反射里面的方法就不特殊说明了,这里说下 获取注解的方法把,如下
// // 获取某个类型的注解 // public <A extends Annotation> A getAnnotation(Class<A> annotationClass); // // 获取所有注解(包括父类中被Inherited修饰的注解) // public Annotation[] getAnnotations(); // // 获取声明的注解(但是不包括父类中被Inherited修饰的注解) // public Annotation[] getDeclaredAnnotations(); // // 判断某个对象上是否被某个注解进行标注 // public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // // // 获取某个类声明的所有字段 // public Field[] getDeclaredFields() throws SecurityException; // // 获取某个方法 // public Method getMethod(String name, Class<?>... parameterTypes);
执行下单元测试: OK
.NetCore Attribute
Java中有的 .NetCore一样能实现,这里就要介绍.NetCore总的特性了,就是Attribute类,怎么来使用这个呢?不要急,通过带来是解释,自定义的特性需要继承Attribute类,且类名可以以Attribute结尾,这样在使用的时候就可以通过前面的名称来写,代码如下
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public class CustomAttribute : Attribute { public string Sql { get; set; } }
看到这里,就有一种熟悉感,看下源码,这里什么Class 等等更Java用法一样标识该特性作用于什么对象上,AllowMultiple :标识是否可以指定多次,同一个对象上多次使用特性,Inherited:当前特性是否可以被继承
// // 摘要: // Specifies the application elements on which it is valid to apply an attribute. [Flags] public enum AttributeTargets { // // 摘要: // Attribute can be applied to an assembly. Assembly = 1, // // 摘要: // Attribute can be applied to a module. Module = 2, // // 摘要: // Attribute can be applied to a class. Class = 4, // // 摘要: // Attribute can be applied to a structure; that is, a value type. Struct = 8, // // 摘要: // Attribute can be applied to an enumeration. Enum = 16, // // 摘要: // Attribute can be applied to a constructor. Constructor = 32, // // 摘要: // Attribute can be applied to a method. Method = 64, // // 摘要: // Attribute can be applied to a property. Property = 128, // // 摘要: // Attribute can be applied to a field. Field = 256, // // 摘要: // Attribute can be applied to an event. Event = 512, // // 摘要: // Attribute can be applied to an interface. Interface = 1024, // // 摘要: // Attribute can be applied to a parameter. Parameter = 2048, // // 摘要: // Attribute can be applied to a delegate. Delegate = 4096, // // 摘要: // Attribute can be applied to a return value. ReturnValue = 8192, // // 摘要: // Attribute can be applied to a generic parameter. GenericParameter = 16384, // // 摘要: // Attribute can be applied to any application element. All = 32767 }
下面我们同样用接口来实现,代码如下,前面说了 自定义属性已Attribute结尾的类名,写的时候直接写Custom
public interface RelactorDao { [Custom(Sql = "select * from user_model where id=1")] void InsertModel(); }
这里我写一个测试类是看下,由于时间的关系,这里就不写SqlHelper 来执行了,输入下Sql就行了,这个跟Java一样需要使用反射,思想一样,只是使用方法名称不同而已,具体的方法就不做介绍..有兴趣自己了解下
public class TestClass { public void TestMethod() { var type = typeof(RelactorDao); MethodInfo methodInfo= type.GetMethod("InsertModel"); var atrrs = methodInfo.GetCustomAttributes(typeof(CustomAttribute), false) as CustomAttribute[]; var strSql = atrrs.First().Sql; //当然这里也可以执行 Console.WriteLine(strSql); } }
接下来我们在看下执行效果 OK
总结
这里只是简单的模拟下,其实要实现MyBatis中的注解的功能,其实还需要其他的知识,面向切面编程的技术AOP
Java中的 @Aspect 注解 ,.NetCore 可以通过动态代理来实现,但是反过来想下,.NetCore中一样可以实现类似于MyBait一样使用方式的ORM框架,可能.NetCore中考虑到大量应用反射会导致性能问题
来源:oschina
链接:https://my.oschina.net/u/2352647/blog/4299339