动态代理实现Spring Aop
Posted 邱慕夏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态代理实现Spring Aop相关的知识,希望对你有一定的参考价值。
引言
我们在前两篇文章中,都为这篇做了铺垫,我们现在来做这样一件事情,在业务逻辑中添加Aop的非业务逻辑。
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(这里用一句话描述这个类的作用)
* @author [qmx]
* @date
*
*/
public class AopClientTest {
public static void main(String[] args) throws Exception {
//初始化容器对象
BeanFactory factory = new ClassPathXmlApplicationContext();
User user = new User();
user.setUserName("hanyankun");
//获取容器中userDao对象
UserDao userDao = (UserDao)factory.getBean("UserDao");
userDao.update(user);
}
}
AspectCacheBean:
package com.tgb.config;
import com.tgb.util.MethodCatch;
/**
* @ClassName: AspectCachBean
* @Description:
* 缓存服务类,实现了对缓存的,前置,后置, 保存的方法
* @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: 认证服务类,提供了认证前, 认证后,认证保存的方法
* @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: 容器接口,提供容器公共服务方法, 增加,删除,遍历,获取对象,遍历类型,容器大小等方法
* @author [qmx]
* @date
*
*/
public interface BeanFactory {
/**
* 获取容器中指定对象
*
* @param id
* 对象名称如: getBean("user")
* @return
*/
public Object getBean(String id);
/**
* 容器中放入对象
*
* @param k
* @param v
* @return
*/
public Object put(String k, Object v);
/**
* 打印容器中所有对象类型
*/
public void printTypeName();
/**
* 获取容器中所有对象 返回类型 Map<string(对象类型),Object(对象)>
*
* @return Map<string(对象类型),Object(对象)>
*/
public Map<String, Object> getAllBean();
/**
* 获取容器所有bean
*/
public void printAllbeanId();
public void remove(String id);
/**
* 容器中对象的数量
* @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 容器组装类, 装载 业务容器 和 切入容器。 分别将其中的 颗粒装载到各自的 beans 中
*/
public class ClassPathXmlApplicationContext implements BeanFactory {
// 业务容器beans
private Map<String, Object> containerBeans = new HashMap<String, Object>();
// 切面容器beans
private Map<String, Object> aspectBeans = new HashMap<String, Object>();
// 设置是否需要aop
private boolean isAop = true;
/*
* 构造函数加载个容器内对象
*/
public ClassPathXmlApplicationContext() throws Exception {
SAXBuilder sb = new SAXBuilder();
// 扫描业务容器对象
Document containerDoc = sb.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("beans.xml"));
// 扫描切入容器对象
Document aspectDoc = sb.build(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("aspecbeans.xml"));
// 设置切面容器
getAspectBeans(aspectDoc);
// 设置业务容器bean
getContainerBeans(containerDoc);
}
/***
* 设置业务容器装配
* @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节点信息
Element aopElement = (Element) root.getChildren("aop").get(0);
//aop节点属性
isAop = Boolean.parseBoolean(aopElement.getAttributeValue("isaop"));
//获取bean节点
List list = root.getChildren("bean");
// 前置增强节点
List aopBeforeList = root.getChildren("aspectbefore");
//后置节点
List aopAfterList = root.getChildren("aspectafter");
//辨别增强节点是否有配置,放入bean关系容器中
if (aopBeforeList != null) {
containerBeans.put("aspectbefore", aopBeforeList);
}
if (aopAfterList != null) {
containerBeans.put("aspectafter", aopAfterList);
}
//调用装备对象方法,装配业务对象
putAllBeans(list, containerBeans);
}
/**
* 设置切入容器装配对象
*
* @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);
}
/**
* 对象装配方法
* @param list 读取的配置文件
* @param allBeans 设置装配的容器对象
* @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++) {
//获取传入父亲节点中的每个子节点,为行element
Element element = (Element) list.get(i);
//获取子节点中的id属性
String id = element.getAttributeValue("id");
//获取子节点中的class属性
String clazz = element.getAttributeValue("class");
//实例化class
Object o = Class.forName(clazz).newInstance();
//将实例化的class放入容器
allBeans.put(id, o);
//for循环获取 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
//调用 依赖实体中的set方法(为子实体的方法)
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);
}
}
}
/**
* 获取容器中指定对象
*
* @param id
* 对象名称如: getBean("user")
* @return
*/
public Object getBean(String id) {
if (!isAop) {
return containerBeans.get(id);
}
return new JDKDynamicProxy(containerBeans.get(id), aspectBeans, containerBeans)
.getProxy();
}
/**
* 容器中放入对象
*
* @param k
* @param v
* @return
*/
public Object put(String k, Object v) {
return containerBeans.put(k, v);
}
/**
* 打印容器中所有对象类型
*/
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);
}
}
/**
* 获取容器中所有对象
*
* @return Map<string(对象类型),Object(对象)>
*/
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;
}
/***
* 删除指定对象
*/
public void remove(String id) {
containerBeans.remove(id);
}
/***
* 打印所有注入对象
*/
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("容器中的对象个数是" + size() + "个");
}
}
/**
* 获取容器中对象的个数
*/
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实现对业务容器 的增强,对业务容器中每个对象增强 服务类中的方法,根据 关系容器配置,
* 实现特性方法增强
* @author [qmx]
*/
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
private Map<String, Object> aspectBeans; // 切入容器
private Map<String, Object> containerBeans;// 业务容器
/**
* 代理类获取代理对象,业务容器,切面容器
*
* @param target
* 被代理对象
* @param aspectBeans
* 切面容器
* @param containerBeans
* 业务容器
*/
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");//获取关系容器中的配置
invokeAspectName(beforeList, method, args);// 调用切面类中匹配方法
Object result = method.invoke(target, args);// 调用 被代理类本身方法
return result;
}
/**
* 拦截方法匹配
*
* @param beforeList
* 拦截器的所有对象
* @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判断获取的集合是否为空,若为空则执行所有服务对象的所有方法
if (beforeList != null && beforeList.size() != 0) {
//for循环遍历 集合对象中的对象,获取每个对象,执行该对象中的方法
for (int i = 0; i < beforeList.size(); i++) {
Element element = (Element) beforeList.get(i); //获取每个对象
String aspectClass = element.getAttributeValue("aspectId");// 获取容器中切入类名称
String aspectName = element.getAttributeValue("aspectMethod");// 执行的切入方法
//若对象为空,则说明
if (aspectBeans.get(aspectClass) == null) {
System.out.println("未找到该切入类,请查看配置的切入类名称是否正确");
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); // 反射调用切入类方法
jinectmethod.invoke(aspectBeans.get(aspectClass), args==null? new Object[1]: args);
}
aspactAllClass(aspectClass, args==null? new Object[1]: args);
}
}
}
//传入集合对象为空,则执行多有对象的所有方法
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); // 反射调用切入类方法
jinectmethod.invoke(entry.getValue(), args==null? new Object[1]: args);
}
}
}
}
}
/**
*
* @Title: aspactAllClass
* @Description: 执行容器中所有服务类中的方法(除了指定的对象不执行,其他的都执行)
* @param @param aspectId
* @param @param args
* @param @throws NoSuchMethodException
* @param @throws SecurityException
* @param @throws IllegalAccessException
* @param @throws IllegalArgumentException
* @param @throws InvocationTargetException 设定文件
* @return void 返回类型
* @throws
*/
public void aspactAllClass(String aspectId, Object[] args)
throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Iterator aspectClass = aspectBeans.entrySet().iterator();
//while循环获取服务集合中的所有对象,调用该对象中的方法
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); // 反射调用切入类方法
jinectmethod.invoke(entry.getValue(), args==null? new Object[1]: args);
}
}
}
}
}
/**
* 执行某个服务类中的所有方法
* @Title: getAllMethod
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @param clazz
* @param @param aspectClass
* @param @param args
* @param @throws IllegalAccessException
* @param @throws IllegalArgumentException
* @param @throws InvocationTargetException
* @param @throws NoSuchMethodException
* @param @throws SecurityException 设定文件
* @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); // 反射调用切入类方法
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(这里用一句话描述这个类的作用)
* @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(这里用一句话描述这个类的作用)
* @author [qmx]
* @date
*
*/
public class UserDaoImpl implements UserDao {
@Override
public void save(User user) {
System.out.println("这是业务类 " + this.getClass()
+ "-----的 userDao.save()方法-----");
}
@Override
public void update(User user) {
System.out.println("这是业务类 " + this.getClass()
+ "-----的 userDao.update()方法-----");
}
@Override
public void delete(User user) {
System.out.println("这是业务类 " + 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 设定文件
* @return String 返回类型
* @throws
*/
public String methodName();
}
aspectbeans.xml:
<beans>
<!-- 服务类配置 -->
<aspectbean id="aspectCachBean" class="com.tgb.config.AspectCachBean"></aspectbean>
<aspectbean id="aspectCertifiyBean" class="com.tgb.config.AspectCertifiyBean"></aspectbean>
</beans>
beans.xml:
<beans>
<!-- 业务类 -->
<bean id="UserDao" class="com.tgb.daoImpl.UserDaoImpl" />
<!-- 是否启用aop -->
<aop isaop="true"></aop>
<!-- 关系配置 -->
<!-- aspectMethod="save" -->
<aspectbefore aspectId="aspectCachBean" method="update" aspectMethod="cacheAfter" ></aspectbefore>
<aspectbefore aspectId="aspectCertifiyBean" method="update" aspectMethod="certifyAfter" ></aspectbefore>
</beans>
以上是关于动态代理实现Spring Aop的主要内容,如果未能解决你的问题,请参考以下文章