从反射到SpringAOP(编写中)
JDK反射的运用
通过反射做Bean字段操作
Tx tx = new OuterPaymentTx();
tx.setId(12);
tx.setTxHandle("copy test");
tx.setInputor("tttare");
tx.setTxChannel(new TxChannel());
//bean copy
Tx newTx = new OuterPaymentTx();
Class<? extends Object> clazz1 = tx.getClass();
Class<? extends Object> newClazz = newTx.getClass();
System.out.println(clazz1 == newClazz);
List<Field> fieldList = new ArrayList<Field>();
//Tx类的继承关系比较复杂,必须通过while循环拿到此类及所有除Object类以外的父类
//获取此类及其付类所有属性
while(clazz1!=null && !clazz1.getName().toLowerCase().equals("java.lang.object")){
fieldList.addAll(Arrays.asList(clazz1.getDeclaredFields()));
clazz1 = clazz1.getSuperclass();
}
//便利属性开始设置
for (int i = 0; i < fieldList.size(); i++) {
Field field = fieldList.get(i);
field.setAccessible(true);
String fieldName = field.getName();
//Class中被static修饰的字段和方法,静态字段将在metaSpace中类常量池中,无关任何class对象实例
//静态方法的调用也与class对象实例无关,可被null或者无关对象调用
Object fieldValue = field.get(tx);//对static修饰的字段,tx换为null或任何值,一样能set值
//Modifier 配合 Class,Field,Method类的getModifiers()属性
//能获取 final,static,private等修饰词
if(!Modifier.isFinal(field.getModifiers())){
//final不可赋值
field.setAccessible(true);//setAccessible,破坏类的封装性(private),不建议使用
field.set(newTx, fieldValue);//对static修饰的字段,newTx换为null或任何值,一样能set值
}
}
System.out.println(newTx.getId()+"|"+newTx.getInputor()+"|"+newTx.getTxChannel());
通过反射对方法的调用
Class clazz = ParamLogAspect.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method m = declaredMethods[i];
m.setAccessible(true);
// Modifier 获取类,字段,方法 private,static,final等修饰属性
if(Modifier.isStatic(m.getModifiers())&&!m.getName().equals("main")){
//static,不需要对象实例,用null和其他对象直接调用
System.out.println(m.invoke(null, "入参"));
}
// Modifier用状态和name排除mian方法和不能调用的方法
if(!Modifier.isStatic(m.getModifiers())&&!m.getName().equals("main")&&!m.getName().equals("around"))
{
//Method实例调用invoke(Class实例,Objects[]方法参数们)
System.out.println(m.invoke(clazz.newInstance(), "非静态入参"));
}
}
JDK实现动态代理
利用jdk的反射实现动态代理,被jdk代理的类一定要实现接口,jdk代理类要实现这个接口,总的来说,jdk代理类与目标类是兄弟关系;
目标对象
/**
* 核心类,执行程序重要方法,需被代理(不实现Payment无法被jdk代理)
* */
public class CorePayment implements Payment {
//核心付款类
public void execut(String payUserNo,String recieveUserNo,double amount) throws InterruptedException{
Thread.sleep(200);
System.out.println(payUserNo+"向"+recieveUserNo+"付款"+amount);
}
}
实现动态代理业务逻辑的类
public class JdkProxy implements InvocationHandler {
/** 需要代理的目标对象 */
private Object targetObject;//JdkProxy构造函数时,需要目标类做参数
public Object invoke(Object proxy, Method method, Object[] objects)
throws Throwable {
//objects被代理方法的参数,可以进行参数校验
//method.getName;获取方法名,可以过滤方法
if(objects.length!=3){
System.out.println("error:付款信息不全,不能执行付款");
return null;
}
if(CastUtil.toDouble(objects[2])>1000.0){
System.out.println("error:付款金额过大");
return null;
}
if(CastUtil.toNotNullString(objects[0]).equals("张三")){
System.out.println("error:张三账户被冻结,不能付款");
return null;
}
try {
//
method.invoke(this.targetObject, objects);
System.out.println("success:成功付款");
} catch (Exception e) {
System.out.println("error:付款失败");
e.printStackTrace();
}
return null;
}
public Object newJdkProxy (Object targetObject){
this.targetObject = targetObject;
//jdk代理,生成代理类需要 目标对象的 classLoader,interface的class对象,和InvocationHandler的实例
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
}
创建动态代理类的工厂方法
Proxy返回代理对象(目标对象的兄弟对象),需要参数,目标对象的classLoader,目标对象Interfaces的class对象,和处理代理业务的类实例(实现了InvocationHandler接口)
public Object newJdkProxy (Object targetObject){
this.targetObject = targetObject;
//jdk代理,生成代理类需要 目标对象的 classLoader,interface的class对象,和InvocationHandler的实例
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
}
测试方法
public static void main(String[] args) throws InterruptedException {
JdkProxy jdkProxy = new JdkProxy();
Payment newJdkProxy = (Payment)jdkProxy.newJdkProxy(new CorePayment());
newJdkProxy.execut("张三", "李四", 500);
}
CGlib实现动态代理
cglib需要引入两个jar包:cglib-2.2.2.jar,asm-3.3.1.jar
实现动态代理业务逻辑的类
/**
* 利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
* 被代理类和其被代理方法 必须能被继承
* */
public class CglibProxy implements MethodInterceptor {
/** CGLib需要代理的目标对象 */
private Object targetObject;
/** */
public Object intercept(Object target, Method method, Object[] objects,
MethodProxy proxy) throws Throwable {
System.out.println("被代理方法'"+method.getName()+"'------");
return method.invoke(this.targetObject, objects);
}
/**
* 生产代理类
* */
public Object newCglibProxy(Object targetObject){
this.targetObject = targetObject;
//enhancer对象实现动态代理需要ASM这个字节码操作工具,故如果cglib和asm版本冲突,new此对象会报错
Enhancer enhancer = new Enhancer();
//将目标类设置为代理类的父类
enhancer.setSuperclass(targetObject.getClass());
//指定实现代理业务的对象(MethodInterceptor的实现类)
enhancer.setCallback(this);
return enhancer.create();
}
}
测试方法
public static void main(String[] args) throws InterruptedException {
CglibProxy cglibProxy = new CglibProxy();
CorePayment corePayment = new CorePayment();
CorePayment newCglibProxy = (CorePayment)cglibProxy.newCglibProxy(corePayment);
newCglibProxy.execut("张三", "李四", 100.0);
}