`

Java Annotation实例:使用Annontaion简化开发

阅读更多

Part I

我并不是在卖弄自己的英语有多少的了不起,只不过对Annotation这一次的解释真的很懊恼,“注解”和“注释”这两个对Annotation的翻译我听着不爽,所以全文都用Annotation来表示。

Part II

相信Java的开发人员对Annotation这个名词一定是非常的熟悉了,如今许多优秀的开源框架,都会提供了Annotation的支持。如Spring、Hibernate、JUnit4等。但是这又是为什么那么多的程序员都热衷于Annotation的使用呢?我个人的原因是因为他确实的简化了我们的操作,虽然这样做使得代码和配置的分离难以实现。

Part III

下面我们就用一个权限控制的例子来说明一下,如何使用Annotation来简化我们的开发。

预期功能:

1. 对于每个用户都设定一个对应的权限。

2. 每个Dao的操作都加入对权限的检查。权限不足则抛出安全异常。

思考:

1. Dao层的方法只关心Dao的操作,对于权限的检查则不需要关心。因此我们可以用AOP来实现对权限的检查(在Java中使用动态代理来实现),实现权限检查和Dao操作的解耦。

2. 每个用户都要有相应的权限,而且每个用户的操作都是在不同的线程上进行,因为我们必须要提供一个用户的权限上下文(RoleContext)来提供对权限的设置和获取。

3. 对于Dao层的实现可以采用面向接口的编码方式,实现各层之间的解耦。由于每个Dao层所对应的实现类只有一个,因此,我们可以把实现类的信息作为元数据写入Dao接口中,所以这里最适合用Annotation来实现。

4. Dao层的方法所需要的权限信息与实现无关,因此这里也可以把权限的信息作为方法的元数据写入,所以这里也十分适合用Annotation来实现。

Part IV

首先我们把项目基本的架子搭建:

package com.gzmu.annotation.dao;
public interface BaseDao { }
package com.gzmu.annotation.dao;
import com.gzmu.annotation.annotation.Implement;
import com.gzmu.annotation.annotation.Permission;
import com.gzmu.annotation.dao.impl.UserDaoImpl;
import com.gzmu.annotation.util.Role;
@Implement(UserDaoImpl.class)
public interface UserDao extends BaseDao {
	
	@Permission({Role.ADMINISTRATOR, Role.SYSTEM})
	void save();
	
	@Permission(Role.SYSTEM)
	void delete();
	
	@Permission({Role.USER, Role.ADMINISTRATOR, Role.SYSTEM})
	void query();
	
}
package com.gzmu.annotation.dao.impl;
import com.gzmu.annotation.dao.UserDao;
public class UserDaoImpl implements UserDao {
	
	@Override
	public void save() {
		System.out.println("UserDaoImpl.save()");
	}
	
	@Override
	public void delete() {
		System.out.println("UserDaoImpl.delete()");
	}
	
	@Override
	public void query() {
		System.out.println("UserDaoImpl.query()");
	}
	
}

RoleContext作为一个提供用户权限上下文的单元存在,使用枚举来实现单例模式,ThreadLocal提供了对当前线程权限数据的访问。

package com.gzmu.annotation.context;
import com.gzmu.annotation.util.Role;
public enum RoleContext {
	
	INSTANCE;
	
	private ThreadLocal<Role> role = new ThreadLocal<Role>();
	
	public Role getCurrentRole() {
		return role.get();
	}
	
	public void setCurrentRole(Role role) {
		this.role.set(role);
	}
	
}

Implment用来指定Dao接口对应的实现类。

package com.gzmu.annotation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.gzmu.annotation.dao.BaseDao;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Implement {
	
	Class<? extends BaseDao> value();
	
}

Permission用于指定Dao层的方法的可访问的人员的访问权限。

package com.gzmu.annotation.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.gzmu.annotation.util.Role;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
	
	Role[] value();
	
}

到这里,这个基本的架子就搭建完成了。接下来,我们就要开始使用动态代理、反射以及Annotation来实现对权限的检查。

Part V

下面我们就要详细的解释一下以下的代码:

DaoProxyFactory.newRoleDaoProxy():

1. 我们提供一个简单的工厂,用于生产一个代理对象。传入一个需要代理的接口,用于产生实现该接口的代理对象。

2. 由于我们的接口上使用Implement这个Annotation来指定这个接口所对应的实现类,所以我们可以获取这个实现类会创建一个实际被代理的对象。

RoleInvocationHandler

1. 顾名思义,这个类就是用来做权限控制的,这个类实现了InvocationHandler。

2. 因为我们已经在接口上定义了哪些方法对应哪些被允许执行这个方法的权限,因此我们可以通过method.getAnnotation(Permission.class)这个方法来获得权限的信息。

3. 迭代方法的允许权限,并与当前线程用户的权限做比较,如果发现两者相等,说明当前用户的权限与方法执行的权限一致,因此跳出循环,执行outter标签后面的方法,允许用户执行。

4. 迭代完成后,当前线程用户的权限没有与方法中定义的权限一致,说明用户无权执行这样的操作,因此跑出安全异常。

package com.gzmu.annotation.util;
import java.lang.annotation.AnnotationFormatError;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.gzmu.annotation.annotation.Implement;
import com.gzmu.annotation.annotation.Permission;
import com.gzmu.annotation.context.RoleContext;
import com.gzmu.annotation.dao.BaseDao;
public abstract class DaoProxyFactory {
	
	@SuppressWarnings("unchecked")
	public static <T> T newRoleDaoProxy(Class<T> dao) {
		Implement implAnnotation = dao.getAnnotation(Implement.class);
		
		if (implAnnotation == null)
			throw new AnnotationFormatError("该接口未定义实现类的注解");
		
		BaseDao implClass = null;
		try {
			implClass = implAnnotation.value().newInstance();
		} catch (Exception e) {
			throw new RuntimeException("该接口所定义的实现类不能被实例化", e);
		}
		
		return (T) Proxy.newProxyInstance(
				DaoProxyFactory.class.getClassLoader(),
				new Class<?>[] { dao },
				new RoleInvocationHandler(implClass)
		);
	}
	
	private static final class RoleInvocationHandler implements InvocationHandler {
		private BaseDao target;
		
		public RoleInvocationHandler(BaseDao target) {
			this.target = target;
		}
		
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			Permission permitAnnotation = method.getAnnotation(Permission.class);
			
			outter:
			if (permitAnnotation != null) {
				Role currentRole = RoleContext.INSTANCE.getCurrentRole();
				for (Role permitRole : permitAnnotation.value()) {
					if (permitRole.equals(currentRole))
						break outter;
				}
				throw new SecurityException("当前用户不允许执行此操作");
			}
			
			return method.invoke(target, args);
		}
		
	}
	
}

Part VI

通过这个例子,我们可以看到,用Annotation来简化我们的开发是如此的简单,世界是如此的美好。很多的程序员都觉得学习Annotation是一种负担,或者说XML可以完全取代Annotation的存在。但是我认为,一个事物的存在,必然有他的价值,没有任何的一个事物是能够完全取代另外一个事物。与其在作无谓的争论,不如花时间去研究如何更好的利用?而且Annotation的队伍这个在不断的壮大,这就是一种最好的证明。

分享到:
评论

相关推荐

    JavaAnnotation实例.docx

    【Java Annotation 实例】 Java Annotation 是一种元数据,它允许我们在源代码中嵌入信息,这些信息可以被编译器或运行时环境用于处理代码。Annotation 不是代码本身,但可以影响代码的行为或提供编译时和运行时的...

    jakarta.annotation-api-1.3.5-API文档-中文版.zip

    Maven坐标:jakarta.annotation:jakarta.annotation-api:1.3.5; 标签:annotation、api、jakarta、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...

    java annotation 实例

    Java注解(Annotation)是Java语言提供的一种元数据机制,用于在代码中插入额外的信息,这些信息可以被编译器或运行时环境读取。它们主要用于简化代码的维护、提高可读性,以及实现编译时和运行时的检查。在本实例中...

    Java Annotation

    Java Annotation 作为一种强大的元数据机制,已经在现代软件开发中扮演着越来越重要的角色。无论是框架设计还是日常编码,理解和灵活运用注解都能极大地提高开发效率和代码质量。随着 Java 技术的发展,我们可以期待...

    jakarta.annotation-api-1.3.5-API文档-中英对照版.zip

    Maven坐标:jakarta.annotation:jakarta.annotation-api:1.3.5; 标签:annotation、api、jakarta、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容...

    javax.annotation-api-1.3.2-API文档-中文版.zip

    Maven坐标:javax.annotation:javax.annotation-api:1.3.2; 标签:annotation、javax、api、jar包、java、API文档、中文版; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 ...

    javax.annotation-api-1.2-API文档-中文版.zip

    Maven坐标:javax.annotation:javax.annotation-api:1.2; 标签:annotation、javax、api、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化...

    用Annotation简化Java程序的开发(PDF)

    ### 用Annotation简化Java程序的开发 #### 一、引言 随着软件开发技术的不断发展,特别是Java语言的广泛应用,开发者面临着如何有效地管理和配置代码的问题。传统的做法是使用XML文件来配置程序的各种设置,但这种...

    java源代码:220个JAVA初学者实例集合

    Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能和丰富的类库而著名。对于初学者来说,通过实例学习是掌握Java语法和编程概念的重要途径。"220个JAVA初学者实例集合"提供了丰富的实践机会,帮助新手...

    JDK5.0 Java Annotation 介绍(ppt)

    1. **定义和使用**:从 JDK5.0 开始,Java 提供了定义和使用自定义 Annotation 的能力。这包括定义 Annotation 类型的语法、声明 Annotation 的语法,以及读取 Annotation 的 API。Annotation 不直接改变代码的执行...

    Java Annotation的讲解和例子

    Java 注解(Annotation)是Java语言的一个重要特性,它为代码提供元数据,即关于代码的信息,但这些信息不直接影响程序的运行。注解在Java中主要用于编译器检查、运行时处理、框架生成元数据等场景。本篇将深入探讨...

    JavaAnnotation必须掌握的特性Java开发Ja

    综上所述,Java注解是一种强大的工具,它简化了代码,增强了可读性,并为开发人员提供了元数据驱动的编程模型。理解和熟练使用Java注解是Java开发中不可或缺的一部分,尤其在构建复杂、模块化的应用和框架时。

    Java 注解Annotation实例上手文档

    ### Java 注解Annotation实例上手文档 #### 一、引言与基础知识 Java注解(Annotation)自JDK 5.0引入以来,已经成为Java语言的重要特性之一,它为代码元数据提供了一种标准化的方式,使得编译器、工具和其他框架...

    Java实战篇:设计自己的Annotation

    接下来,我们可以在方法上使用自定义的`@TestMethod` Annotation: ```java public class Example { @TestMethod(description = "This is a test method.") public void myTestMethod() { System.out.println(...

    java annotation demo

    总结来说,Java注解是增强代码可读性、简化代码维护和提高开发效率的重要工具。通过创建和使用注解,我们可以将元数据嵌入到代码中,而这些数据可以在编译时或运行时被解析和利用。在"java annotation demo"中,你...

    JavaAnnotation手册[借鉴].pdf

    这些Annotation在Java企业应用开发中非常有用,可以简化管理和控制组件的生命周期。 总结,Java Annotation是一个强大的工具,它增强了代码的元数据能力,使得开发者可以更灵活地处理代码的编译、运行和维护。通过...

    JavaAnnotation手册.pdf

    1. 标准Annotation:Java 5引入了一些预定义的Annotation,如`@Override`、`@Deprecated`、`@ SuppressWarnings`等,这些标准Annotation由Java编译器直接支持。从Java 6开始,自定义Annotation的使用也得到了增强,...

Global site tag (gtag.js) - Google Analytics