SpringAOP——JDK动态代理

Posted 杨晨光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringAOP——JDK动态代理相关的知识,希望对你有一定的参考价值。

       Spring的动态代理有两种:一是JDK的动态代理(需要提供接口);另一个是cglib动态代理(通过修改字节码来实现代理)。大部分情况下,一般使用JDK动态代理,因为JDK动态代理的速度要比CGLIB要快,在SpringAOP中,如果一个Bean有接口声明,那么Spring就会使用JDK动态代理代理它,否则启用CGLIB。今天咱们主要讨论JDK动态代理的方式。JDK的代理方式主要就是通过反射跟动态编译来实现的。

       反射上一篇文章已经说过了(Java反射),这里就不在做论述。我们先了解一下动态代理。

       假如,A是一个软件工程师,A所在的公司是一个软件公司。现在,B为客户,B需要A所在的软件公司开发一款软件。显然,B需要找的是A公司的商务,跟商务进行沟通。最终,软件的开发由A来落实。在这里边,A公司的商务就相当于一个代理。代理的实际就是在真实服务对象(A)之前,加一个代理对象(商务)。这个代理对象,可以根据调用者(B)的要求去控制真实服务对象(A)的访问。

       代理模式的好处:可以增加一些服务,同时可以根据需要选择是否需要启用真实服务对象。


扯了半天,下边进入正题,JDK动态代理

需要提供一个简单的接口

 public interface HelloService 
  
	    public void sayHello(String name); 
 
 实现类 

public class HelloServiceImpl implements HelloService 
 
	    @Override 
        public void sayHello(String name) 
	     
		 System.err.println("hello " + name); 
	    
 


 

接着,需要生成代理对象(proxy),分成两步:

1.生成代理对象需要建立代理对象(proxy)和真实对象(HelloServiceImpl)的代理关系

2.实现代理方法

在JDK动态代理中需要实现接口:java.lang.reflect.InvocationHandler.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 

public class HelloProxy implements InvocationHandler 
 
	private Object target; 
	
	/** 
	 * 生成代理对象,并和真实服务对象绑定. 
	 * @param target 真实服务对线下 
	 * @return 代理对象 */ 
	public Object bind(Object target) 
	 
		this.target = target; 
		
		//生成代理对象,并绑定. 
		Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //类的加载器 
						      target.getClass().getInterfaces(), //对象的接口,明确代理对象挂在哪些接口下 
						      this);//指明代理类,this代表用当前类对象,那么就要求其实现InvocationHandler接口的invoke方法 
		
		return proxy; 
	 
		
	/** 
	 * 当生成代理对象时,第三个指定使用HelloProxy进行代理时,代理对象调用的方法就会进入这个方法。 
	 * @param proxy ——代理对象 
	 * @param method -- 被调用的方法 
	 * @param args -- 方法参数 
	 * @return 代理方法返回。 
	 * @throws Throwable -- 异常处理 */ 
	 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
	  
		System.err.println("反射真实对象方法前"); 
		Object obj = method.invoke(target, args);//相当于sayHello方法调用. 
		System.err.println("反射真实对象方法后"); 
		
		return obj; 
	


说明一下上边的代码:

首先声明了一个类的属性target,它的作用是保存真实服务对象(B);然后用bind方法绑定代理对象(proxy商务)和真实对象(A)。

用之前的比喻就是proxy就是商务,它代理了target(A),而商务代理的逻辑方法放在this这个对象的invoke方法中,只是this这个对象需要实现InvocationHandler接口而已。这样,声明就会进入当前类的invoke方法中,它实现的是代理逻辑,它有三个参数

Object proxy——当前代理对象(商务)

Method method——当前调度的方法

Object[] args——方法参数

然后我们通过反射调度真实对象的方法,Object obj = method.invoke(target, args);//相当于sayHello方法调用,实现功能。

控制台进行打印

public class Chapter1Main 
 
	public static void main(String[] args) 
	 
		HelloProxy helloProxy = new HelloProxy();
		//因为使用了接口HelloService绑定了代理对象,所以可以用HelloService作为代理对象的声明. 
		HelloService proxy = (HelloService) helloProxy.bind(new HelloServiceImpl()); 
		proxy.sayHello("张三");//此时使用代理对象运行方法进入HelloProxy的invoke方法里 
	 

打印出来的结果

反射真实对象方法前
hello 张三
反射真实对象方法后

至此,HelloService实际上已经是一个代理对象了。


以上是关于SpringAOP——JDK动态代理的主要内容,如果未能解决你的问题,请参考以下文章

SpringAOP——JDK动态代理

SpringAOP-JDK 动态代理和 CGLIB 代理

基础篇——代理模式之SpringAOP

3.123(什么是springAOP)(AOP术语)(JDK动态代理)

Spring 04 -SpringAOP开发

SpringAop学习