Spring笔记(补充)

3.数学计算器的改进

在最初,我们需要在实现加减乘除的时候,加入日志,这使得

  • 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。

  • 代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
    然后我们通过动态代理的方式进行改进:

动态代理的两种方式:

  1. 基于接口:jdk动态代理
  2. 基于继承:Cglib、Javassist动态代理
    在此演示基于接口的,基于接口,也就是接口中定义了什么方法,就可以通过代理对象去执行这些方法,而接口中没有定义的,就无法代理;而基于继承的方式,定义了什么方法,就可以全部代理

基于接口:接下来是生成动态代理对象的两种方法

3.1 通过newProxyInstance()生成代理对象

ArithmeticCalculatorProxy.java

package com.atguigu.spring.aop.proxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 生成代理对象。
 * 
 * JDK的动态代理:
 * 	 1. Proxy : 是所有动态代理类的父类, 专门用户生成代理类或者是代理对象  
 * 		 	public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
                            用于生成代理类的Class对象. 
                                         
 * 			public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                         InvocationHandler h)
                            用于生成代理对象                            
                                         
 *   2. InvocationHandler :完成动态代理的整个过程.
 *   		public Object invoke(Object proxy, Method method, Object[] args)
        	throws Throwable; 
 *   		
 */
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();
		
		
		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 ;
	}
	
}


/**
 * 模拟底层生成的动态代理类
 * 是在运行过程中动态生成的
 */

class $Proxy0  extends Proxy  implements ArithmeticCalculator{

	//这个h就是我们实现的匿名对象
	protected $Proxy0(InvocationHandler h) {
		super(h);
	}

	@Override
	public int add(int i, int j) {
	//	return  super.h.invoke(this,方法对象,方法参数);
		return 0 ;
	}

	@Override
	public int sub(int i, int j) {
		return 0;
	}

	@Override
	public int mul(int i, int j) {
		return 0;
	}

	@Override
	public int div(int i, int j) {
		return 0;
	}
	
}

Main.java 同时将动态生成的代理类保存下来

package com.atguigu.spring.aop.proxy;

import java.util.Properties;

public class Main {
	
	public static void main(String[] args)  throws Exception{
		//将动态生成的代理类保存下来
		 Properties properties = System.getProperties();
		 properties.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

		
		
		//目标对象
		ArithmeticCalculator target = new ArithmeticCalculatorImpl();
		
		//获取代理对象
		Object  obj = new ArithmeticCalculatorProxy2(target).getProxy();
		
		// 转回具体的类型.
		//接口类型
		ArithmeticCalculator  proxy = (ArithmeticCalculator) obj ;
		
		System.out.println(proxy.getClass().getName());
		
		//
		int result = proxy.add(1, 1);
		
		System.out.println("Main  Result : " + result );
		
		
		/**
		 * 问题:
		 * 	  1. 代理对象能否转换成目标对象的类型?
		 *    2. 代理对象调用代理方法,为什么会执行 InvocationHandler中的invoke 方法   :   见手动模拟底层生成的动态代理类
		 */
		
	}
}

3.2 使用getProxyClass()生成代理类的Class对象
package com.atguigu.spring.aop.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 生成代理对象。
 * 
 * JDK的动态代理:
 * 	 1. Proxy : 是所有动态代理类的父类, 专门用户生成代理类或者是代理对象  
 * 		 	public static Class<?> getProxyClass(ClassLoader loader,
                                         Class<?>... interfaces)
                            用于生成代理类的Class对象. 
                                         
 * 			public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                         InvocationHandler h)
                            用于生成代理对象                            
                                         
 *   2. InvocationHandler :完成动态代理的整个过程.
 *   		public Object invoke(Object proxy, Method method, Object[] args)
        	throws Throwable; 
 *   		
 */
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 ;
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值