【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实际上已经是一个代理对象了。


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值