6、动态代理

6.1、静态代理回顾

6.1.1、代码实现

package cn.org.kingdom.proxy;
interface Subject{
	public void getMoney();
}
class RealSubject implements Subject{
	@Override
	public void getMoney() {
		System.out.println("求求你,能不能还我钱");
	}
}
class Proxy implements Subject{
	private Subject subject;
	public Subject getSubject() {
		return subject;
	}
	public void setSubject(Subject subject) {
		this.subject = subject;
	}
	public void preGetMoney(){
		System.out.println("带上大砍刀");
	}
	@Override
	public void getMoney() {
		preGetMoney();
		subject.getMoney();
		afterGetMoney();
	}
	public void afterGetMoney(){
		System.out.println("赔偿精神损失费,拿去佣金");
	}
}
public class ProxyTest {
	public static void main(String[] args) {
		RealSubject real = new RealSubject() ; 
		Proxy p = new Proxy();
		p.setSubject(real);
		p.getMoney();
	}
}

6.1.2、静态代理

1、代理对象完全包含真实对象,客户端使用的都是代理对象上面的方法,和真实对象无关;

2、静态代理能够处理把不是真实对象该做的事情从真实对象上面撇开;

3、静态代理带来的问题:需要为每一个真实对象都得创建一个代理对象,导致类会急剧增加

6.2、动态代理

6.2.1、jdk的动态代理

/**
	ClassLoader loader:类加载器
	Class<?>[] interfaces:要实现的接口
	InvocationHandler h:调用处理器
	return :代理对象
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){}
/**
	proxy:生成的代理对象
	method:当前调用的真实方法
	args: 当前调用方法的实参
	return : 真实方法的返回结果
*/
public Object invoke(Object proxy, Method method, Object[] args) {}    

参考代码

package cn.org.kingdom.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.org.kingdom.ts.Transation;
public class MyinvocationHanlder implements InvocationHandler {
	//真实角色
	private Object obj ;  //obj必须实现接口(jdk原生动态代理)
    //ts附加功能对象
	private Transation ts ; 
	public MyinvocationHanlder() {
		super();
	}
	public MyinvocationHanlder(Object obj, Transation ts) {
		super();
		this.obj = obj;
		this.ts = ts;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
	public Transation getTs() {
		return ts;
	}
	public void setTs(Transation ts) {
		this.ts = ts;
	}
	public Object getProxy(){
		return 
				Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object value = null ; 
		if(obj.getClass().getName().endsWith("ServiceImpl")){
			if("add".equals(method.getName())||"insert".equals(method.getName())) {
                //aop要植入的操作
				try{
					ts.begin();
					value= method.invoke(obj, args);
					int c= 10/0;
					ts.commit();
				}catch(Exception e)  {
					ts.rollback();
				}
				return value;
 			}else{
 				method.invoke(obj, args);
 			}
		}	
		return null;
	}
}

JDK动态代理

①代理的对象必须要实现一个接口;

②需要为每个对象创建代理对象;

③动态代理的最小单位是类(所有类中的方法都会被处理);

JDK动态代理总结

①JAVA动态代理是使用java.lang.reflect包中的Proxy类与InvocationHandler接口这两个来完成的。

②要使用JDK动态代理,必须要定义接口。

③JDK动态代理将会拦截所有pubic的方法(因为只能调用接口中定义的方法),这样即使在接口中增加了新的方法,不用修改代码也会被拦截。

④如果只想拦截一部分方法,可以在invoke方法中对要执行的方法名进行判断

6.2.2、CGLIB动态代理

若一个类,没有接口如何代理 ?

javassist.jar:Struts2的代理实现方案.

cglib.jar:Spring的代理实现方案

java类实现

public class TransactionCallback implements org.springframework.cglib.proxy.InvocationHandler {
	private Object target;//真实对象
	private TransactionManager txManager;
	//不需要事务的方法
	private String[] methodNames = { "update", "get" };
	public TransactionCallback(Object target, TransactionManager txManager) {
		this.target = target;
		this.txManager = txManager;
	}
	//创建代理对象
	public Object getProxyInstance() {
		Enhancer enhancer = new Enhancer();
		enhancer.setClassLoader(this.getClass().getClassLoader());
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}
	public Object invoke(Object proxy, Method method, Object[] args){
		Object ret = null;
		if(Arrays.asList(methodNames).contains(method.getName())){
			method.invoke(target, args);
			return null;
		}
		txManager.beginTransaction();
		try {
			method.invoke(target, args);
			txManager.commint();
		} catch (Exception e) {
			txManager.rollback();
		}
		return ret;
	}
}

总结:

CGLIB代理总结:

①CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。

②要求类不能是final的,要拦截的方法要是非final、非static、非private的。

③动态代理的最小单位是类(所有类中的方法都会被处理);

代理总结:

Spring中:

1、若目标对象实现了若干接口,spring就会使用JDK动态代理。

2、若目标对象没有实现任何接口,spring就使用CGLIB库生成目标对象的子类。对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。

posted @ 2021-04-09 13:47  Mirindasky  阅读(62)  评论(0编辑  收藏  举报