国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

Java Annotation實(shí)例:使用Annontaion簡(jiǎn)化開發(fā)

2019-11-06 08:19:44
字體:
供稿:網(wǎng)友

轉(zhuǎn)載地址:http://kentkwan.iteye.com/blog/739513

Part I

我并不是在賣弄自己的英語(yǔ)有多少的了不起,只不過對(duì)Annotation這一次的解釋真的很懊惱,“注解”和“注釋”這兩個(gè)對(duì)Annotation的翻譯我聽著不爽,所以全文都用Annotation來表示。

Part II

相信java的開發(fā)人員對(duì)Annotation這個(gè)名詞一定是非常的熟悉了,如今許多優(yōu)秀的開源框架,都會(huì)提供了Annotation的支持。如SPRing、Hibernate、JUnit4等。但是這又是為什么那么多的程序員都熱衷于Annotation的使用呢?我個(gè)人的原因是因?yàn)樗_實(shí)的簡(jiǎn)化了我們的操作,雖然這樣做使得代碼和配置的分離難以實(shí)現(xiàn)。

Part III

下面我們就用一個(gè)權(quán)限控制的例子來說明一下,如何使用Annotation來簡(jiǎn)化我們的開發(fā)。

預(yù)期功能:

1. 對(duì)于每個(gè)用戶都設(shè)定一個(gè)對(duì)應(yīng)的權(quán)限。

2. 每個(gè)Dao的操作都加入對(duì)權(quán)限的檢查。權(quán)限不足則拋出安全異常。

思考:

1. Dao層的方法只關(guān)心Dao的操作,對(duì)于權(quán)限的檢查則不需要關(guān)心。因此我們可以用AOP來實(shí)現(xiàn)對(duì)權(quán)限的檢查(在Java中使用動(dòng)態(tài)代理來實(shí)現(xiàn)),實(shí)現(xiàn)權(quán)限檢查和Dao操作的解耦。

2. 每個(gè)用戶都要有相應(yīng)的權(quán)限,而且每個(gè)用戶的操作都是在不同的線程上進(jìn)行,因?yàn)槲覀儽仨氁峁┮粋€(gè)用戶的權(quán)限上下文(RoleContext)來提供對(duì)權(quán)限的設(shè)置和獲取。

3. 對(duì)于Dao層的實(shí)現(xiàn)可以采用面向接口的編碼方式,實(shí)現(xiàn)各層之間的解耦。由于每個(gè)Dao層所對(duì)應(yīng)的實(shí)現(xiàn)類只有一個(gè),因此,我們可以把實(shí)現(xiàn)類的信息作為元數(shù)據(jù)寫入Dao接口中,所以這里最適合用Annotation來實(shí)現(xiàn)。

4. Dao層的方法所需要的權(quán)限信息與實(shí)現(xiàn)無關(guān),因此這里也可以把權(quán)限的信息作為方法的元數(shù)據(jù)寫入,所以這里也十分適合用Annotation來實(shí)現(xiàn)。

Part IV

首先我們把項(xiàng)目基本的架子搭建:

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作為一個(gè)提供用戶權(quán)限上下文的單元存在,使用枚舉來實(shí)現(xiàn)單例模式,ThreadLocal提供了對(duì)當(dāng)前線程權(quán)限數(shù)據(jù)的訪問。

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接口對(duì)應(yīng)的實(shí)現(xiàn)類。

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層的方法的可訪問的人員的訪問權(quán)限。

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

到這里,這個(gè)基本的架子就搭建完成了。接下來,我們就要開始使用動(dòng)態(tài)代理、反射以及Annotation來實(shí)現(xiàn)對(duì)權(quán)限的檢查。

Part V

下面我們就要詳細(xì)的解釋一下以下的代碼:

DaoProxyFactory.newRoleDaoProxy():

1. 我們提供一個(gè)簡(jiǎn)單的工廠,用于生產(chǎn)一個(gè)代理對(duì)象。傳入一個(gè)需要代理的接口,用于產(chǎn)生實(shí)現(xiàn)該接口的代理對(duì)象。

2. 由于我們的接口上使用Implement這個(gè)Annotation來指定這個(gè)接口所對(duì)應(yīng)的實(shí)現(xiàn)類,所以我們可以獲取這個(gè)實(shí)現(xiàn)類會(huì)創(chuàng)建一個(gè)實(shí)際被代理的對(duì)象。

RoleInvocationHandler

1. 顧名思義,這個(gè)類就是用來做權(quán)限控制的,這個(gè)類實(shí)現(xiàn)了InvocationHandler。

2. 因?yàn)槲覀円呀?jīng)在接口上定義了哪些方法對(duì)應(yīng)哪些被允許執(zhí)行這個(gè)方法的權(quán)限,因此我們可以通過method.getAnnotation(Permission.class)這個(gè)方法來獲得權(quán)限的信息。

3. 迭代方法的允許權(quán)限,并與當(dāng)前線程用戶的權(quán)限做比較,如果發(fā)現(xiàn)兩者相等,說明當(dāng)前用戶的權(quán)限與方法執(zhí)行的權(quán)限一致,因此跳出循環(huán),執(zhí)行outter標(biāo)簽后面的方法,允許用戶執(zhí)行。

4. 迭代完成后,當(dāng)前線程用戶的權(quán)限沒有與方法中定義的權(quán)限一致,說明用戶無權(quán)執(zhí)行這樣的操作,因此跑出安全異常。

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("該接口未定義實(shí)現(xiàn)類的注解");
		
		BaseDao implClass = null;
		try {
			implClass = implAnnotation.value().newInstance();
		} catch (Exception e) {
			throw new RuntimeException("該接口所定義的實(shí)現(xiàn)類不能被實(shí)例化", 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("當(dāng)前用戶不允許執(zhí)行此操作");
			}
			
			return method.invoke(target, args);
		}
		
	}
	
}

Part VI

通過這個(gè)例子,我們可以看到,用Annotation來簡(jiǎn)化我們的開發(fā)是如此的簡(jiǎn)單,世界是如此的美好。很多的程序員都覺得學(xué)習(xí)Annotation是一種負(fù)擔(dān),或者說xml可以完全取代Annotation的存在。但是我認(rèn)為,一個(gè)事物的存在,必然有他的價(jià)值,沒有任何的一個(gè)事物是能夠完全取代另外一個(gè)事物。與其在作無謂的爭(zhēng)論,不如花時(shí)間去研究如何更好的利用?而且Annotation的隊(duì)伍這個(gè)在不斷的壯大,這就是一種最好的證明。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 盘锦市| 九江市| 平乐县| 苏州市| 贵定县| 千阳县| 蓬莱市| 曲阜市| 平凉市| 津市市| 景东| 潢川县| 响水县| 兴业县| 柳林县| 临海市| 芮城县| 北宁市| 化州市| 开原市| 察雅县| 盘山县| 无极县| 开平市| 三穗县| 文化| 富蕴县| 临潭县| 全南县| 称多县| 洪湖市| 永清县| 文昌市| 吉木乃县| 桂林市| 泾源县| 青岛市| 体育| 梁山县| 互助| 南漳县|