小言_互联网的博客

SSM学习—Spring(第五天学习记录)

317人阅读  评论(0)

AOP前景提要

提出问题

①代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
②代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。

动态代理

  • 代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
  • 代理的方式
 - 基于接口的动态代理:JDK动态代理

  		   Proxy:所有动态代理类的父类,专门用户生成代理类或者代理对象
               public static Class<?> getProxyClass(ClassLoader loader,
                                               Class<?>... interfaces)
                                  用于生成代理类的Class对象.
               public static Object newProxyInstance(ClassLoader loader,
                                                Class<?>[] interfaces,
                                               InvocationHandler h)
                                  用于生成代理对象
          InvocationHandler :完成动态代理的整个过程.
       		public Object invoke(Object proxy, Method method, Object[] args)
              	throws Throwable;
 


附上代码:

public interface ArithmeticCalculator {
    public  int   add(int i,int j);
    public  int sub(int i,int j);
    public  int mul(int i,int j);
    public int div(int i,int j);
}

public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

	@Override
	public int add(int i, int j) {
		int result = i + j ; 
		return result ; 
	}

	@Override
	public int sub(int i, int j) {
		int result = i - j ; 
		return result ; 
	}

	@Override
	public int mul(int i, int j) {
		int result = i * j ; 
		return result ; 
	}

	@Override
	public int div(int i, int j) {
		int result = i / j ; 
		return result ;
	}
	}


创建InvocationHandler类,实现InvocationHandler接口,这个类中持有一个被代理对象的实例target。InvocationHandler中有一个invoke方法,所有执行代理对象的方法都会被替换成执行invoke方法。再在invoke方法中执行被代理对象target的相应方法。当然,在代理过程中,我们在真正执行被代理对象的方法前加入自己其他处理。这也是Spring中的AOP实现的主要原理,这里还涉及到很重要的关于java反射方面的基础知识。

	public class ArithmeticCalculatorProxy {
	//目标对象
	private  ArithmeticCalculator  target ; 
	
	public ArithmeticCalculatorProxy(ArithmeticCalculator target) {
		this.target = target ; 
	}
	//获取代理对象的方法
	public Object  getProxy() {
		//代理对象
		Object  proxy ; 
		/**
		 * loader:  ClassLoader对象。 类加载器对象.  帮我们加载动态生成的代理类。 
		 * 
		 * interfaces: 接口们.  提供目标对象的所有的接口.  目的是让代理对象保证与目标对象都有接口中想同的方法. 
		 * 			
		 * h:  InvocationHandler类型的对象. 
		 */
		ClassLoader loader = target.getClass().getClassLoader();
		
		Class []  interfaces = target.getClass().getInterfaces();
		
		//执行newProxyInstance不会调用invoke
		proxy = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			/**
			 * invoke:  代理对象调用代理方法, 会回来调用invoke方法。
			 * 
			 * proxy: 代理对象 , 在invoke方法中一般不会使用. 
			 * 
			 * method: 正在被调用的方法对象. 
			 * 
			 * args:   正在被调用的方法的参数. 
			 */
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				
				//将方法的调用转回到目标对象上. 
				
				//获取方法的名字
				String methodName = method.getName();
				//记录日志
				System.out.println("LoggingProxy==> The method " + methodName+" begin with "+ Arrays.asList(args));
				Object result = method.invoke(target, args);  // 目标对象执行目标方法. 相当于执行ArithmeticCalculatorImpl中的+ - * /
				
				//记录日志
				System.out.println("LoggingProxy==> The method " + methodName  +" ends with :" +result   );
				return result ;
			}
		});
		
		return proxy ;
	}
	
}

JDK动态代理的另外一种方式

public class ArithmeticCalculatorProxy2 {
	//动态代理:    目标对象     如何获取代理对象      代理要做什么 
	
	//目标对象
	private  ArithmeticCalculator  target ; 
	
	
	public ArithmeticCalculatorProxy2(ArithmeticCalculator target) {
		this.target = target ; 
	}
	
	
	//获取代理对象的方法
	public Object  getProxy() throws Exception {
		
		//代理对象
		Object  proxy ; 
		
		ClassLoader loader = target.getClass().getClassLoader();
		Class [] interfaces = target.getClass().getInterfaces();
		
		Class proxyClass = Proxy.getProxyClass(loader, interfaces);
		
		//Class  创建对象?   newInstance()
		
		Constructor con = 
				proxyClass.getDeclaredConstructor(InvocationHandler.class);
		
		proxy = con.newInstance(new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				//将方法的调用转回到目标对象上. 
				
				//获取方法的名字
				String methodName = method.getName();
				//记录日志
				System.out.println("LoggingProxy2==> The method " + methodName+" begin with "+ Arrays.asList(args));
				Object result = method.invoke(target, args);  // 目标对象执行目标方法. 相当于执行ArithmeticCalculatorImpl中的+ - * /
				
				//记录日志
				System.out.println("LoggingProxy2==> The method " + methodName  +" ends with :" +result   );
				return result ;
			}
		});
		
		
		return proxy ;
	}
	
}

创建代理对象并进行测试

 public static void main(String[] args) {
           //将动态生成的proxy保存下来
        Properties properties = System.getProperties();
        properties.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        //目标对象
        ArithmeticCalculator target =new ArithmeticCalculatorimpl();
        //获取代理对象
        Object obj=new Proxy(target).getProxy();
        ArithmeticCalculator arithmeticCalculator=(ArithmeticCalculator)obj;
        System.out.println(arithmeticCalculator.getClass().getName());
        System.out.println(arithmeticCalculator.add(1,2));
    }

测试结果如下

生成的Proxy

package com.atguigu.spring.aop.proxy;

import com.atguigu.spring.aop.proxy.ArithmeticCalculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy00 extends Proxy implements ArithmeticCalculator {
	private static Method m1;
	private static Method m2;
	private static Method m4;
	private static Method m3;
	private static Method m6;
	private static Method m5;
	private static Method m0;

	public $Proxy00(InvocationHandler arg0) throws  {
      super(arg0);
   }

	public final boolean equals(Object arg0) throws  {
      try {
         return ((Boolean)super.h.invoke(this, m1, new Object[]{arg0})).booleanValue();
         //这里又返回了InvocationHandler中的invoke方法
      } catch (RuntimeException | Error arg2) {
         throw arg2;
      } catch (Throwable arg3) {
         throw new UndeclaredThrowableException(arg3);
      }
   }

	public final String toString() throws  {
      try {
         return (String)super.h.invoke(this, m2, (Object[])null);
      } catch (RuntimeException | Error arg1) {
         throw arg1;
      } catch (Throwable arg2) {
         throw new UndeclaredThrowableException(arg2);
      }
   }

	public final int mul(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m4, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int add(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int sub(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m6, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int div(int arg0, int arg1) throws  {
      try {
         return ((Integer)super.h.invoke(this, m5, new Object[]{Integer.valueOf(arg0), Integer.valueOf(arg1)})).intValue();
      } catch (RuntimeException | Error arg3) {
         throw arg3;
      } catch (Throwable arg4) {
         throw new UndeclaredThrowableException(arg4);
      }
   }

	public final int hashCode() throws  {
      try {
         return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
      } catch (RuntimeException | Error arg1) {
         throw arg1;
      } catch (Throwable arg2) {
         throw new UndeclaredThrowableException(arg2);
      }
   }

	static {
		try {
			m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
			m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
			m4 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("mul",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m3 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("add",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m6 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("sub",
					new Class[]{Integer.TYPE, Integer.TYPE});
			m5 = Class.forName("com.atguigu.spring.aop.proxy.ArithmeticCalculator").getMethod("div",
					new Class[]{Integer.TYPE, Integer.TYPE});
		    m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
		} catch (NoSuchMethodException arg1) {
			throw new NoSuchMethodError(arg1.getMessage());
		} catch (ClassNotFoundException arg2) {
			throw new NoClassDefFoundError(arg2.getMessage());
		}
	}
}

结束语

代理对象能否转换成目标对象的类型?
代理对象调用代理方法,为什么会执行 InvocationHandler中的invoke 方法?


转载:https://blog.csdn.net/qq_39728274/article/details/105074343
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场