发表于: 2020-03-10 23:24:00
1 1262
用java 的动态代理实现AOP来了解AOP的原理.
1. 创建一个接口测试类
public interface UserDao {
int insertUser();
void updateUser();
void findUser();
void deleteUser();
}
public class UserDaoImpl implements UserDao {
@Override
public int insertUser() {
System.out.println("insertUser() 添加执行了....");
return 111;
}
@Override
public void updateUser() {
System.out.println("updateUser() 更新执行了....");
}
@Override
public void findUser() {
System.out.println("查找....");
}
@Override
public void deleteUser() {
System.out.println("deleteUser() 删除执行了....");
}
}
实现Java动态代理接口 InvocationHandler 重写invoke()方法
package com.jnshu.InvocationHandleraop.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理
**/
// 要使用java的动态代理必须实现它的InvocationHandler接口方法invoke()
public class LogIntercept implements InvocationHandler{
// 准备接收代理对象的属性
// 动态代理的好处,被封装的对象是Object类型,接受任意类型的对象
private Object terget;
// 设置要代理的方法对象
public void setTerget(Object terget) {
this.terget = terget;
}
// 插入到代理方法开始前
public void beforeMethod(){
System.out.println("接口方法 开始...");
}
// 插入到代理方法接收后
public void afterMethod(){
System.out.println("接口方法 结束...");
}
/**
* 重写的 InvocationHandler 动态代理接口方法
* method是调用的方法,即需要执行的方法;args是方法的参数;
* Proxy懒得查
*
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法执行前运行
beforeMethod();
// 执行代理的方法 无论调用代理对象的哪个方法,invoke方法都要被调用
method.invoke(terget, args);
// 在方法执行后运行
afterMethod();
return null;
}
}
测试
package com.jnshu.InvocationHandleraop.dao;
import com.jnshu.springaop.dao.UserDao;
import com.jnshu.springaop.dao.impl.UserDaoImpl;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import static org.junit.Assert.*;
public class LogInterceptTest {
//test:生成代理实例,并调用了updateUser()方法
@Test
public void invoke() {
// 抽象角色(动态代理只能代理接口)
UserDao userDao = new UserDaoImpl();
// 创建代理对象
LogIntercept logIntercept = new LogIntercept();
// 指定被代理的接口对象
logIntercept.setTerget(userDao);
// 一次性生成代理 使用Proxy的newProxyInstance去代理接口对象的,内部再去调用 LogIntercept中重写的invoke, 不是直接调用重写的 invoke方法
UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
// getClass():取得当前对象所属的Class对象
// getClassLoader():取得该Class对象的类装载器,保证是和 类 类型同一个加载器加载的
userDao.getClass().getClassLoader(),
// 为一个class数组分配空间,并且第一个元素是UserDao类, 这个我也看不懂=.=
new Class[]{UserDao.class},
// 传入代理对象
logIntercept
);
// 这里可以通过运行结果证明userDaoProxy是Proxy的一个实例,这个实例实现了userDao接口
System.out.println((userDaoProxy instanceof Proxy) + " 这里证明userDaoProxy是Proxy的一个实例,这个实例实现了userDaoProxy接口");
// 这里可以看出userDaoProxy的Class类是$Proxy4,这个$Proxy4类继承了Proxy,实现了userDao接口
System.out.println("userDaoProxy的Class类是:" + userDaoProxy.getClass().toString());
System.out.print("userDaoProxy中的属性有:\n");
// getDeclaredFields()方法和Java的反射机制有关.
// 返回 Field 对象的一个数组,该数组包含此 Class 对象所表示的类或接口所声明的所有字段(包括私有成员)
Field[] field = userDaoProxy.getClass().getDeclaredFields();
// 遍历 field 集合
for (Field field1 : field) {
System.out.println(field1.getName() + ", ");
}
System.out.println("userDaoProxy的父类是:" + userDaoProxy.getClass().getSuperclass());
System.out.print("userDaoProxy实现的接口是:");
// getInterfaces()方法和Java的反射机制有关. 它能够获得这个对象所实现的接口。
Class<?>[] interfaces = userDaoProxy.getClass().getInterfaces();
for (Class<?> i : interfaces) {
System.out.print(i.getName() + "\n");
}
// 执行接口方法测试
System.out.println("\n===测试接口是否被代理了===");
userDaoProxy.updateUser();
System.out.println("");
userDaoProxy.deleteUser();
}
}
输出结果,已被成功代理 :
true 这里证明userDaoProxy是Proxy的一个实例,这个实例实现了userDaoProxy接口
userDaoProxy的Class类是:class com.sun.proxy.$Proxy4
userDaoProxy中的属性有:
m1,
m5,
m2,
m6,
m0,
m3,
m4,
userDaoProxy的父类是:class java.lang.reflect.Proxy
userDaoProxy实现的接口是:com.jnshu.springaop.dao.UserDao
---测试接口是否被代理了---
接口方法 开始...
updateUser() 更新执行了....
接口方法 结束...
接口方法 开始...
deleteUser() 删除执行了....
接口方法 结束...
结果:没有显示的调用invoke()方法,方法却执行了。
今日问题 无
评论