Spring 代理模式

>一个例子 房客租房子:

---------------------------------------------------------------------------------

中介要遵循一定的规范:接口 Premises 类

---------------------------------------------------------------------------------

中介:Rent 类

出租房屋功能:rent() ,但执行出租房屋的功能,房东来执行

---------------------------------------------------------------------------------

房东:Houser类

出租房屋功能:rent()

---------------------------------------------------------------------------------
房客:Client类

---------------------------------------------------------------------------------

>静态代理(百无一用,用就用动态)

Houser:

public class Houser implements Preises{
	public void rent() {//领域业务 更纯粹
		System.out.println("出租房屋!");
	}
}

Rent:

public class Rent implements Preises {
    
	private Houser houser=new Houser();
	
	private void haveLook(){
		System.out.println("带房客看房!");
	}
	
	@Override
	public void rent() {//实际开发过程中:领域业务、公共业务
		this.haveLook();
		houser.rent();
		this.money();
	}

	private void money(){
		System.out.println("收取中介费!");
	}
}

Premises:

public interface Preises {
public void rent();
}

Client:

public class Client {
public static void main(String[] args) {
	Rent rent=new Rent();
	rent.rent();
}
}

角色类型:领域业务,Houser

代理角色:Rent,中介

抽象角色:接口

好处:在开发过程中,让领域业务更加纯粹,不与其他业务耦合。

缺点:增加了开发的复杂度,每有一个领域业务(真实角色),就要针对该领域业务,再写一个代理角色。

>动态代理:(代理角色不再去实际创建,而是去动态生成)

作用:动态的去修改一个已经存在的类的方法

(再说下反射:可以通过java代码,解析另外的java代码,自己解析自己

想象一下,一个方法go(String className,String methodName){

//在这个go方法里,如何根据类名,方法名调用传入类名类的指定名称方法?

//答:反射!})

两种方式(推荐使用cglib):

基于接口的动态代理:jdk(不需要依赖第三方类库)

基于类的动态代理:cglib

>基于接口的动态代理:

(反射:自己分析自己,java通过反射可以分析一个类的结构,可以执行一个类的方法)

在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理或动态代理对象。

代理类是在内存中生成的。

>hello jdk 动态代理

AInterf接口:

package com.langsin.testProxy;

public interface AInterf {
public void f1();
public void f2();
}

AImpl实现:

public class AImpl implements AInterf {

	@Override
	public void f1() {
		System.out.println("f1");	
	}

	@Override
	public void f2() {
		System.out.println("f2");		
	}

}

代理生成类:

public class ProxyBuilder implements InvocationHandler{
	private AInterf a;
	public ProxyBuilder(AInterf a) {
		this.a=a;
	}
	public AInterf bind(){
		//Proxy类的newProxyInstance方法 就是要创建一个类 (这个类:第一,也是AInterf接口的实现类;第二,还是AImpl的动态代理类,实现代理功能)
		//为什么要让生成的这个家伙(代理)也去实现 AInterf ? 因为在内存中压根就没有一个类能接收它
		return (AInterf) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{AInterf.class}, this);
		//                             	            参数:   当前类的类加载器 (当前工程所有都是同一个类加载器)    返回值(dynamic代理类)要实现的接口              InvocationHandler对象				
	    
	}
	
		
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result=null;
		if ("f1".equals(method.getName())) {
			System.out.println("你没有权限!");
		}
		if ("f2".equals(method.getName())) {
			System.out.println("欢迎光临!");
			System.out.println("before");
			result=method.invoke(a, args);//放行原始类的方法执行
			System.out.println("after");
		}
		return result;
	}

}

测试类: 

public class Run {
public static void main(String[] args) {
	AInterf a=new AImpl();
	AInterf ap = new ProxyBuilder(a).bind();
	//这里ap 接收了代理类的父类对象 调用的是代理类中 的 f1 f2方法
	//而且 每次调用 都会去走ProxyBuilder的 invoke方法
	ap.f1();
	ap.f2();
}
}

练习:比如当调用ArrayList的以add名字开头的方法时,去打印一句话,怎么做?

public class ProxyBuilder implements InvocationHandler{
	private List list;
	public ProxyBuilder(List list) {
		this.list=list;
	}
	public List bind(){
		//Proxy类的newProxyInstance方法 就是要创建一个类 (这个类:第一,也是AInterf接口的实现类;第二,还是AImpl的动态代理类,实现代理功能)
		//为什么要让生成的这个家伙(代理)也去实现 AInterf ? 因为在内存中压根就没有一个类能接收它
		return (List) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{List.class}, this);
		//                             	            参数:   当前类的类加载器 (当前工程所有都是同一个类加载器)    返回值(dynamic代理类)要实现的接口              InvocationHandler对象				
	    
	}
	
		
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result=null;
		if (method.getName().startsWith("add")) {
			System.out.println("欢迎添加数据!");
			method.invoke(list, args);
		}else {
			result=method.invoke(list, args);//放行原始类的方法执行
		}
		return result;
	}

}

>基于cglib的动态代理:

基于jdk的Proxy的局限性:被代理的那个哥们,必须要实现一个接口。

ForumServiceImpl  
package com.langsin.cglibproxy;

public class ForumServiceImpl  {

	public void removeTopic(int topicId) {
		System.out.println("模拟删除Topic记录:"+topicId);
	}

	public void removeForum(int forumId) {
		System.out.println("模拟删除Forum记录:"+forumId);
	}
}
CglibProxy
package com.langsin.cglibproxy;

import java.lang.reflect.Method;

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

public class CglibProxy implements MethodInterceptor {
	private Enhancer enhancer = new Enhancer();

	public Object getProxy(Class clazz) {
		enhancer.setSuperclass(clazz);
		enhancer.setCallback(this);
		return enhancer.create();
	}
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		System.out.println("检查权限");
		Object result = proxy.invokeSuper(obj, args);
		System.out.println("善后处理");
		return null;
		
	}
}
TestForumService
package com.langsin.cglibproxy;

public class TestForumService {
	public static void main(String[] args) {
		
		CglibProxy proxy = new CglibProxy();
		ForumServiceImpl forumService = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);
		forumService.removeForum(10);
		forumService.removeTopic(1023);
	}
}

猜你喜欢

转载自blog.csdn.net/AhaQianxun/article/details/94129284