動(dòng)態(tài)代理實(shí)現(xiàn)Spring Aop
來源:程序員人生 發(fā)布時(shí)間:2016-06-25 15:32:16 閱讀次數(shù):3415次
引言
我們在前兩篇文章中,都為這篇做了鋪墊,我們現(xiàn)在來做這樣1件事情,在業(yè)務(wù)邏輯中添加Aop的非業(yè)務(wù)邏輯。

AopClinetTest:
package com.tgb.client;
import com.tgb.config.BeanFactory;
import com.tgb.config.ClassPathXmlApplicationContext;
import com.tgb.dao.UserDao;
import com.tgb.domain.User;
/**
* AOP效果測試
* @ClassName: AopClientTest
* @Description: TODO(這里用1句話描寫這個(gè)類的作用)
* @author [qmx]
* @date
*
*/
public class AopClientTest {
public static void main(String[] args) throws Exception {
//初始化容器對(duì)象
BeanFactory factory = new ClassPathXmlApplicationContext();
User user = new User();
user.setUserName("hanyankun");
//獲得容器中userDao對(duì)象
UserDao userDao = (UserDao)factory.getBean("UserDao");
userDao.update(user);
}
}
AspectCacheBean:
package com.tgb.config;
import com.tgb.util.MethodCatch;
/**
* @ClassName: AspectCachBean
* @Description:
* 緩存服務(wù)類,實(shí)現(xiàn)了對(duì)緩存的,前置,后置, 保存的方法
* @author [qmx]
* @date
*
*/
public class AspectCachBean {
@MethodCatch(methodName="cacheBefore")
public void cacheBefore(Object proxy) {
System.out.println("---這是切入 類AspectCachBean cacheBefore()-方法--");
}
@MethodCatch(methodName="cacheAfter")
public static void cacheAfter(Object proxy) {
System.out.println("---這是切入 類AspectCachBean cacheAfter()-方法--");
}
@MethodCatch(methodName="cacheSave")
public void cacheSave(Object proxy){
System.out.println("---這是切入 類AspectCachBean cacheSave()-方法--");
}
}
AspectCertifiyBean:
package com.tgb.config;
import com.tgb.util.MethodCatch;
/**
*
* @ClassName: AspectCertifiyBean
* @Description: 認(rèn)證服務(wù)類,提供了認(rèn)證前, 認(rèn)證后,認(rèn)證保存的方法
* @author [qmx]
* @date
*
*/
public class AspectCertifiyBean {
@MethodCatch(methodName = "certifiyBefore")
public void certifiyBefore(Object proxy) {
System.out.println("---這是切入 類AspectCertifiyBean certifiyBefore()-方法--");
}
@MethodCatch(methodName = "certifyAfter")
public void certifyAfter(Object proxy) {
System.out.println("---這是切入 類AspectCertifiyBean certifyAfter()-方法--");
}
@MethodCatch(methodName = "certifySave")
public void certifySave(Object proxy) {
System.out.println("---這是切入 類AspectCertifiyBean certifySave()-方法--");
}
}
BeanFactory:
package com.tgb.config;
import java.util.List;
import java.util.Map;
/**
*
* @ClassName: ContainerBeans
* @Description: 容器接口,提供容器公共服務(wù)方法, 增加,刪除,遍歷,獲得對(duì)象,遍歷類型,容器大小等方法
* @author [qmx]
* @date
*
*/
public interface BeanFactory {
/**
* 獲得容器中指定對(duì)象
*
* @param id
* 對(duì)象名稱如: getBean("user")
* @return
*/
public Object getBean(String id);
/**
* 容器中放入對(duì)象
*
* @param k
* @param v
* @return
*/
public Object put(String k, Object v);
/**
* 打印容器中所有對(duì)象類型
*/
public void printTypeName();
/**
* 獲得容器中所有對(duì)象 返回類型 Map<string(對(duì)象類型),Object(對(duì)象)>
*
* @return Map<string(對(duì)象類型),Object(對(duì)象)>
*/
public Map<String, Object> getAllBean();
/**
* 獲得容器所有bean
*/
public void printAllbeanId();
public void remove(String id);
/**
* 容器中對(duì)象的數(shù)量
* @return
*/
public int size();
}
ClassPathXmlApplicationContext:
package com.tgb.config;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import net.sf.cglib.asm.ClassVisitor;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
/***
*
*
* @author 容器組裝類, 裝載 業(yè)務(wù)容器 和 切入容器。 分別將其中的 顆粒裝載到各自的 beans 中
*/
public class ClassPathXmlApplicationContext implements BeanFactory {
// 業(yè)務(wù)容器beans
private Map<String, Object> containerBeans = new HashMap<String, Object>();
// 切面容器beans
private Map<String, Object> aspectBeans = new HashMap<String, Object>();
// 設(shè)置是不是需要aop
private boolean isAop = true;
/*
* 構(gòu)造函數(shù)加載個(gè)容器內(nèi)對(duì)象
*/
public ClassPathXmlApplicationContext() throws Exception {
SAXBuilder sb = new SAXBuilder();
// 掃描業(yè)務(wù)容器對(duì)象
Document containerDoc = sb.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("beans.xml"));
// 掃描切入容器對(duì)象
Document aspectDoc = sb.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("aspecbeans.xml"));
// 設(shè)置切面容器
getAspectBeans(aspectDoc);
// 設(shè)置業(yè)務(wù)容器bean
getContainerBeans(containerDoc);
}
/***
* 設(shè)置業(yè)務(wù)容器裝配
* @param doc
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
private void getContainerBeans(Document doc) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, NoSuchMethodException,
SecurityException, IllegalArgumentException, InvocationTargetException {
//讀取文檔根目錄
Element root = doc.getRootElement();
//獲得aop節(jié)點(diǎn)信息
Element aopElement = (Element) root.getChildren("aop").get(0);
//aop節(jié)點(diǎn)屬性
isAop = Boolean.parseBoolean(aopElement.getAttributeValue("isaop"));
//獲得bean節(jié)點(diǎn)
List list = root.getChildren("bean");
// 前置增強(qiáng)節(jié)點(diǎn)
List aopBeforeList = root.getChildren("aspectbefore");
//后置節(jié)點(diǎn)
List aopAfterList = root.getChildren("aspectafter");
//辨別增強(qiáng)節(jié)點(diǎn)是不是有配置,放入bean關(guān)系容器中
if (aopBeforeList != null) {
containerBeans.put("aspectbefore", aopBeforeList);
}
if (aopAfterList != null) {
containerBeans.put("aspectafter", aopAfterList);
}
//調(diào)用設(shè)備對(duì)象方法,裝配業(yè)務(wù)對(duì)象
putAllBeans(list, containerBeans);
}
/**
* 設(shè)置切入容器裝配對(duì)象
*
* @param doc
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws SecurityException
* @throws NoSuchMethodException
*/
private void getAspectBeans(Document doc) throws InstantiationException,
IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//讀取文檔根目錄
Element root = doc.getRootElement();
List aspectElements = root.getChildren("aspectbean");//讀取切入配置文件
putAllBeans(aspectElements,aspectBeans);
}
/**
* 對(duì)象裝配方法
* @param list 讀取的配置文件
* @param allBeans 設(shè)置裝配的容器對(duì)象
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public void putAllBeans(List list, Map<String, Object> allBeans)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException, NoSuchMethodException, SecurityException,
IllegalArgumentException, InvocationTargetException {
for (int i = 0; i < list.size(); i++) {
//獲得傳入父親節(jié)點(diǎn)中的每一個(gè)子節(jié)點(diǎn),為行element
Element element = (Element) list.get(i);
//獲得子節(jié)點(diǎn)中的id屬性
String id = element.getAttributeValue("id");
//獲得子節(jié)點(diǎn)中的class屬性
String clazz = element.getAttributeValue("class");
//實(shí)例化class
Object o = Class.forName(clazz).newInstance();
//將實(shí)例化的class放入容器
allBeans.put(id, o);
//for循環(huán)獲得 bean中的 屬性property
for (Element propertyElement : (List<Element>) element
.getChildren("property")) {
//獲得property屬性中的name屬性
String name = propertyElement.getAttributeValue("name"); // userDAO
//獲得property屬性中的ref屬性
String bean = propertyElement.getAttributeValue("ref"); //
//獲得子屬性的試題
Object beanObject = allBeans.get(bean);// UserDAOImpl
//調(diào)用 依賴實(shí)體中的set方法(為籽實(shí)體的方法)
String methodName = "set" + name.substring(0, 1).toUpperCase()
+ name.substring(1);
Method m = o.getClass().getMethod(methodName,
beanObject.getClass().getInterfaces()[0]);
m.invoke(o, beanObject);
}
}
}
/**
* 獲得容器中指定對(duì)象
*
* @param id
* 對(duì)象名稱如: getBean("user")
* @return
*/
public Object getBean(String id) {
if (!isAop) {
return containerBeans.get(id);
}
return new JDKDynamicProxy(containerBeans.get(id), aspectBeans, containerBeans)
.getProxy();
}
/**
* 容器中放入對(duì)象
*
* @param k
* @param v
* @return
*/
public Object put(String k, Object v) {
return containerBeans.put(k, v);
}
/**
* 打印容器中所有對(duì)象類型
*/
public void printTypeName() {
Set<String> hashSet = new HashSet<String>();
Set<Entry<String, Object>> entryset = containerBeans.entrySet();
{
Iterator iterator = entryset.iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = (Entry<String, Object>) iterator.next();
hashSet.add(entry.getValue().getClass().getSimpleName());
}
}
for (String setType : hashSet) {
System.out.println(setType);
}
}
/**
* 獲得容器中所有對(duì)象
*
* @return Map<string(對(duì)象類型),Object(對(duì)象)>
*/
public Map<String, Object> getAllBean() {
Map<String, Object> beanList = new HashMap<String, Object>();
Iterator iterator = containerBeans.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = (Entry<String, Object>) iterator.next();
beanList.put(entry.getValue().getClass().getSimpleName(), entry.getValue());
}
return beanList;
}
/***
* 刪除指定對(duì)象
*/
public void remove(String id) {
containerBeans.remove(id);
}
/***
* 打印所有注入對(duì)象
*/
public void printAllbeanId() {
Set<Entry<String, Object>> entryset = containerBeans.entrySet();
Set<String> linkSet = new TreeSet<String>();
{
Iterator iterator = entryset.iterator();
while (iterator.hasNext()) {
Entry<String, Object> entry = (Entry<String, Object>) iterator.next();
linkSet.add(entry.getKey());
// System.out.println(entry.getKey());
}
System.out.println(linkSet.toString());
System.out.println("容器中的對(duì)象個(gè)數(shù)是" + size() + "個(gè)");
}
}
/**
* 獲得容器中對(duì)象的個(gè)數(shù)
*/
public int size() {
return containerBeans.size();
}
}
JDKDynamicProxy:
package com.tgb.config;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.jdom.Element;
import com.tgb.util.MethodCatch;
/* @ClassName: JDKDynamicProxy
* @Description: AOP實(shí)現(xiàn)對(duì)業(yè)務(wù)容器 的增強(qiáng),對(duì)業(yè)務(wù)容器中每一個(gè)對(duì)象增強(qiáng) 服務(wù)類中的方法,根據(jù) 關(guān)系容器配置,
* 實(shí)現(xiàn)特性方法增強(qiáng)
* @author [qmx]
*/
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
private Map<String, Object> aspectBeans; // 切入容器
private Map<String, Object> containerBeans;// 業(yè)務(wù)容器
/**
* 代理類獲得代理對(duì)象,業(yè)務(wù)容器,切面容器
*
* @param target
* 被代理對(duì)象
* @param aspectBeans
* 切面容器
* @param containerBeans
* 業(yè)務(wù)容器
*/
public JDKDynamicProxy(Object target, Map<String, Object> aspectBeans,
Map<String, Object> containerBeans) {
this.target = target;
this.aspectBeans = aspectBeans;
this.containerBeans = containerBeans;
}
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target
.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
List beforeList = (List) containerBeans.get("aspectbefore");//獲得關(guān)系容器中的配置
invokeAspectName(beforeList, method, args);// 調(diào)用切面類中匹配方法
Object result = method.invoke(target, args);// 調(diào)用 被代理類本身方法
return result;
}
/**
* 攔截方法匹配
*
* @param beforeList
* 攔截器的所有對(duì)象
* @param method
* @param args
* @throws NoSuchMethodException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
public void invokeAspectName(List beforeList, Method method, Object[] args)
throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
//if判斷獲得的集合是不是為空,若為空則履行所有服務(wù)對(duì)象的所有方法
if (beforeList != null && beforeList.size() != 0) {
//for循環(huán)遍歷 集合對(duì)象中的對(duì)象,獲得每一個(gè)對(duì)象,履行該對(duì)象中的方法
for (int i = 0; i < beforeList.size(); i++) {
Element element = (Element) beforeList.get(i); //獲得每一個(gè)對(duì)象
String aspectClass = element.getAttributeValue("aspectId");// 獲得容器中切入類名稱
String aspectName = element.getAttributeValue("aspectMethod");// 履行的切入方法
//若對(duì)象為空,則說明
if (aspectBeans.get(aspectClass) == null) {
System.out.println("未找到該切入類,請(qǐng)查看配置的切入類名稱是不是正確");
return;
}
Class clazz = aspectBeans.get(aspectClass).getClass(); // 獲得切入類
String elementMethod = element.getAttributeValue("method");// 獲得被切入類方法
// 未聲明切入方法,則履行所有切入方法
if (aspectName == null) {
if (method.getName() != null) {
if (method.getName().equals(elementMethod)) {
getAllMethod(clazz, aspectClass, args);
}
}
aspactAllClass(aspectClass, args==null? new Object[1]: args);
} else {
//if判斷是不是 聲明l切入方法,若是則履行指定切入方法,否則履行所有方法
if (method.getName().equals(elementMethod)) {
Method jinectmethod = clazz.getMethod(aspectName, Object.class); // 反射調(diào)用切入類方法
jinectmethod.invoke(aspectBeans.get(aspectClass), args==null? new Object[1]: args);
}
aspactAllClass(aspectClass, args==null? new Object[1]: args);
}
}
}
//傳入集合對(duì)象為空,則履行多有對(duì)象的所有方法
else {
Iterator aspectClass = aspectBeans.entrySet().iterator();
while (aspectClass.hasNext()) {
Entry<String, Object> entry = (Entry<String, Object>) aspectClass.next();
Class clazz = entry.getValue().getClass();// 獲得切入類
Method[] methods = clazz.getMethods();
for (int j = 0; j < methods.length; j++) {
// 讀取切入類注解中的所有方法
if (methods[j].isAnnotationPresent(MethodCatch.class) == true) {
MethodCatch methodCatch = methods[j]
.getAnnotation(MethodCatch.class);// 獲得注解類
Method jinectmethod = clazz.getMethod(methodCatch.methodName(),
Object.class); // 反射調(diào)用切入類方法
jinectmethod.invoke(entry.getValue(), args==null? new Object[1]: args);
}
}
}
}
}
/**
*
* @Title: aspactAllClass
* @Description: 履行容器中所有服務(wù)類中的方法(除指定的對(duì)象不履行,其他的都履行)
* @param @param aspectId
* @param @param args
* @param @throws NoSuchMethodException
* @param @throws SecurityException
* @param @throws IllegalAccessException
* @param @throws IllegalArgumentException
* @param @throws InvocationTargetException 設(shè)定文件
* @return void 返回類型
* @throws
*/
public void aspactAllClass(String aspectId, Object[] args)
throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Iterator aspectClass = aspectBeans.entrySet().iterator();
//while循環(huán)獲得服務(wù)集合中的所有對(duì)象,調(diào)用該對(duì)象中的方法
while (aspectClass.hasNext()) {
Entry<String, Object> entry = (Entry<String, Object>) aspectClass.next();
if (!aspectId.equals(entry.getKey())) {
Class clazz = entry.getValue().getClass();// 獲得切入類
Method[] methods = clazz.getMethods();
for (int j = 0; j < methods.length; j++) {
// 讀取切入類注解中的所有方法
if (methods[j].isAnnotationPresent(MethodCatch.class) == true) {
MethodCatch methodCatch = methods[j]
.getAnnotation(MethodCatch.class);// 獲得注解類
Method jinectmethod = clazz.getMethod(methodCatch.methodName(),
Object.class); // 反射調(diào)用切入類方法
jinectmethod.invoke(entry.getValue(), args==null? new Object[1]: args);
}
}
}
}
}
/**
* 履行某個(gè)服務(wù)類中的所有方法
* @Title: getAllMethod
* @Description: TODO(這里用1句話描寫這個(gè)方法的作用)
* @param @param clazz
* @param @param aspectClass
* @param @param args
* @param @throws IllegalAccessException
* @param @throws IllegalArgumentException
* @param @throws InvocationTargetException
* @param @throws NoSuchMethodException
* @param @throws SecurityException 設(shè)定文件
* @return void 返回類型
* @throws
*/
public void getAllMethod(Class clazz, String aspectClass, Object[] args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException, SecurityException {
Method[] methods = clazz.getMethods();
for (int j = 0; j < methods.length; j++) {
if (methods[j].isAnnotationPresent(MethodCatch.class) == true) {
MethodCatch methodCatch = methods[j].getAnnotation(MethodCatch.class);// 獲得注解類
Method jinectmethod = clazz.getMethod(methodCatch.methodName(),
Object.class); // 反射調(diào)用切入類方法
jinectmethod.invoke(aspectBeans.get(aspectClass), args==null? new Object[1]: args);
}
}
}
}
UserDao:
package com.tgb.dao;
import com.tgb.domain.User;
/**
* 用于操作用戶信息類。
* @ClassName: UserDao
* @Description: TODO(這里用1句話描寫這個(gè)類的作用)
* @author [qmx]
* @date
*
*/
public interface UserDao {
void save(User user);
void update(User user);
public void delete( User user);
}
UserDaoImpl:
package com.tgb.daoImpl;
import com.tgb.dao.UserDao;
import com.tgb.domain.User;
/**
* 用戶操作類,用于添加用戶信息
*
* @ClassName: UserDaoImpl
* @Description: TODO(這里用1句話描寫這個(gè)類的作用)
* @author [qmx]
* @date
*
*/
public class UserDaoImpl implements UserDao {
@Override
public void save(User user) {
System.out.println("這是業(yè)務(wù)類 " + this.getClass()
+ "-----的 userDao.save()方法-----");
}
@Override
public void update(User user) {
System.out.println("這是業(yè)務(wù)類 " + this.getClass()
+ "-----的 userDao.update()方法-----");
}
@Override
public void delete(User user) {
System.out.println("這是業(yè)務(wù)類 " + this.getClass()
+ "-----的 userDao.delete()方法-----");
}
}
User:
package com.tgb.domain;
public class User {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
MethodCatch:
package com.tgb.util;
/**
* 自定義注解類,用于類方法上讀取方法名稱
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodCatch {
/**
* 用于 獲得方法名稱
* @Title: methodName
* @Description:
* @param @return 設(shè)定文件
* @return String 返回類型
* @throws
*/
public String methodName();
}
aspectbeans.xml:
<beans>
<!-- 服務(wù)類配置 -->
<aspectbean id="aspectCachBean" class="com.tgb.config.AspectCachBean"></aspectbean>
<aspectbean id="aspectCertifiyBean" class="com.tgb.config.AspectCertifiyBean"></aspectbean>
</beans>
beans.xml:
<beans>
<!-- 業(yè)務(wù)類 -->
<bean id="UserDao" class="com.tgb.daoImpl.UserDaoImpl" />
<!-- 是不是啟用aop -->
<aop isaop="true"></aop>
<!-- 關(guān)系配置 -->
<!-- aspectMethod="save" -->
<aspectbefore aspectId="aspectCachBean" method="update" aspectMethod="cacheAfter" ></aspectbefore>
<aspectbefore aspectId="aspectCertifiyBean" method="update" aspectMethod="certifyAfter" ></aspectbefore>
</beans>
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)