Spring AOP的代理模式详解

Spring AOP的代理模式详解


代理模式:代理模式的英文叫做ProxySurrogate,中文都可译为代理,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用


抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以是使用代理主题

代理主题(Proxy)角色代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象。


真实主题角色定义了代理角色所代表地真实对象


JDK动态代理:

面向接口生成代理,原理就是类加载器根据接口,在虚拟机内部创建接口实现类 

Proxy.newProxyInstance(classloader,interfaces[], invocationhandler );


首先编写一个接口Fly:

public interface Fly {

	public void gotoFly();
	
	public void stopFly();
}


编写一个Bird类

public class Bird implements Fly{

	@Override
	public void gotoFly() {
		System.out.println("鸟儿张开翅膀要飞起来了。。。。");
	}

	@Override
	public void stopFly() {
		System.out.println("准备停飞。。。。");
	}
	
	public void eatBug(){
		System.out.println("鸟要吃虫子,补充体力。。。");
	}

}



下面编写一个代理的测试类


</pre><pre name="code" class="java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.junit.Test;

public class ProxyTest {

	@Test
	public void demo1(){
		// JDK 自动代理 的原理是  根据 类加载器和接口  创建代理类(此代理类是接口的实现类,所以必须使用接口
		
		// 1、 创建真是业务对象的引用
		Fly fly = new Bird();
		
		Fly proxy = (Fly) Proxy.newProxyInstance(fly.getClass().getClassLoader(), fly.getClass().getInterfaces(), new InvocationHandler() {
			// 2、使用真是业务对象类加载器和接口,在内存中创建代理对象
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				// 拦截方法
				if(method.getName().equals("gotoFly")){
					System.out.println("被拦截了,鸟飞不走了。。。");
					return null;
				}
				// 不拦截就invoke
				return method.invoke(proxy, args);
			}
		});
		
		proxy.gotoFly();
	}
}



因为创建出来的这个代理类,一定是接口的子类,所以JDK动态代理一定要有接口,并且真实的业务类要实现该接口。

为什么说创建出来的代理类一定是接口的子类,看这个在最后  proxy 调用发放的时候 eclipse提示的信息就可以看出来,只有 Fly()  接口里面的两个方法  gotoFly()  和  stopFly()  并没有 Bird() 类中的 独有的方法。


所以说这个创建出来的代理类就是这个接口的子类。


其实可以大致推出来在java虚拟机里创建的代理类的样子


public void $Proxy0 implements Fly(){
	public void gotoFly(){
		handler.invoke(this,method,args());
	}
}

当执行proxy.gotoFly();这个方法的时候,其实就会调用  Proxy.newProxyInstance(....{

invoke(.....)

})

方法。

所以说可以  在 

 Proxy.newProxyInstance(....{

invoke(.....)

})

这个方法里控制对真是对象方法的访问。


cglib 动态代理

使用范围:对于不适用接口的业务类,无法使用JDK动态代理

原理:CGlib采用非常底层的字节码技术,可以为一个类创建子类,解决无接口类的代理类问题。


下面看一下CGlib动态代理的过程;

首先编写一个业务类,不实现任何的接口:

/**
 * 该业务类没有实现任何接口
 * @author dell
 *
 */
public class Cat {

	public void run(){
		System.out.println("猫可以跑步。。。捉老鼠");
	}
}


接着写一个动态代理的测试类:

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

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.junit.Test;

public class ProxyTest {
	
	@Test
	public void demo2(){
		// cglib 动态代理  在目标业务类没有实现接口的情况下
		
		// 1、创建真实业务对象的引用
		Cat cat = new Cat();
		// 2、创建真实业务类的子类
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(cat.getClass());
		
		// 3、设置回调函数
		enhancer.setCallback(new MethodInterceptor() {
			
			@Override
			public Object intercept(Object proxy, Method method, Object[] args,
					MethodProxy methodProxy) throws Throwable {
				if(method.getName().equals("run")){
					System.out.println("cat的run方法被拦截了。。。。");
					Object invoke = method.invoke(proxy, args);
					System.out.println("真实方法拦截之后。。。。");
					return invoke;
				}
				
				// 不拦截
				return method.invoke(proxy, args);
			}
		});
		Cat proxy = (Cat) enhancer.create();
		
		proxy.run();
	}
}



  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值