代理模式,静态,动态java,cglib代理

静态代理

就是一对一辅导,一个代理类服务一个目标类,调用他的方法,加上一些代理来做的事,增强的动作和目标动作分开,解耦,不至于牵一发而动全身。
静态代理模式的缺点:

1、假设一个系统中有100个Service,则需要创建100个代理对象

2、如果一个Service中有很多方法需要事务(增强动作),发现代理对象的方法中还是有很多重复的代码

动态代理

就是重用行,反射的机制拿到方法,再调用代理进行方法增强,就是 ivoke方法,目标,增强类都是参数了,就是动态的了,不再是一对一。

1.JDK动态代理

流程:原来是有目标类,代理类,要写一个实现invocationnHandoller拦截器的类,有目标和增强类,有参构造,最主要invoke()方法,参数是,代理类target,函数(这是反射或取得),函数的参数args,里面调用mathed.invoke(target,args),返回值返回invoke1的返回值。
服务层接口


public interface PersonService {
	
	public String savePerson();
	
	public void updatePerson();
	
	public void deletePerson();
	
}

实现类

 
public class PersonServiceImpl implements PersonService{
 
	@Override
	public String savePerson() {
		System.out.println("添加");
		return "保存成功!";
	}
 
	@Override
	public void updatePerson() {
		System.out.println("修改");
	}
 
	@Override
	public void deletePerson() {
		System.out.println("删除");
	}
 
}

代理类:


public class MyTransaction {
	public void beginTransaction(){
		System.out.println("开启事务 ");
	}
	public void commit(){
		System.out.println("提交事务");
	}
}

在动态代理在生成代理对象的时候需要一个拦截器 InvocationHandler 因此咱们需要写一个拦截器
springaop也是,不过是封装了

package com.cj.study.proxyjdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class PersonServiceInterceptor implements InvocationHandler{
	//目标类
	private Object target;
	//增强类
	private MyTransaction myTransaction;
	//构造函数注入目标类和增强类
	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
		this.target = target;
		this.myTransaction = myTransaction;
	}
 
	//代理类的每一个方法被调用的时候都会调用下边的这个invoke方法
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		this.myTransaction.beginTransaction();
		//方法的调用,反射,传入的是目标对象,对应函数的参数args
		Object returnValue = method.invoke(this.target, args);
		this.myTransaction.commit();
		return returnValue;
	}
	
}

1、当客户端执行代理对象.方法时,进入到了拦截器的invoke方法体,就是调用代理累的方法都会走这个invoke

2、拦截器中invoke方法体的内容就是代理对象方法体的内容

3、拦截器中invoke方法的method参数是在调用的时候反射获取的

3.测试

package com.cj.study.proxyjdk;
 
import java.lang.reflect.Proxy;
import org.junit.Test;
 
public class ProxyTest {
	@Test
	public void test(){
		//获得目标类
		Object target = new PersonServiceImpl();
		//代理类
		MyTransaction myTransaction = new MyTransaction();
		//处理器,传入
		PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction);
		//下面就是反射获取代理对象,personService 实际上是已经是代理的方法了$Proxy
		PersonService personService = (PersonService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),interceptor);
		//调用方法,会走invoke方法
		String returnValue = (String)personService.savePerson();
		System.out.println(returnValue);
	}
}

2.cglib
首先需要导入cglib的jar包:cglib-nodep-2.1_3.jar
还是接口,实现类,代理类
不同的是拦截器
流程:写拦截器,导入两个目标,代理类,全餐构造,intercept代替了那个invoke,参数代理对象,函数(反射动态获取),函数的参数。代理对象函数的参数,

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 PersonServiceInterceptor implements MethodInterceptor{
	//目标类
	private Object target;
	//增强类
	private MyTransaction myTransaction;
	//构造函数注入目标类和增强类
	public PersonServiceInterceptor(Object target,MyTransaction myTransaction){
		this.target = target;
		this.myTransaction = myTransaction;
	}
	
	public Object createProxy(){
		Enhancer enhancer = new Enhancer();
		enhancer.setCallback(this);
		enhancer.setSuperclass(this.target.getClass());
		return enhancer.create();
	}
 
	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		myTransaction.beginTransaction();
		Object returnValue = arg1.invoke(this.target, arg2);
		myTransaction.commit();
		return returnValue;
	}
	
}

测试

package com.cj.study.proxycglib;
 
import org.junit.Test;
 
public class ProxyTest {
	@Test
	public void test(){
	、、目标
		Object target = new PersonServiceImpl();
		//代理
		MyTransaction myTransaction = new MyTransaction();
		//拦截器,处理
		PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction);
		//不
		PersonService personService =(PersonService) interceptor.createProxy();
		String returnValue = (String)personService.savePerson();
		System.out.println(returnValue);
	}
}

但是还是需要自己去生成代理对象,自己手写拦截器,在拦截器里自己手动的去把要增强的内容和目标方法结合起来
有了Spring的AOP后,就不用自己去写了,只需要在配置文件里进行配置,配置好后Spring按照你的配置去帮你生成代理对象(IOC),按照你的配置把增强的内容和目标方法结合起来(AOP)。就相当于自己写代码也能实现和aop类似的功能,但是有了Spring aop以后有些事情Spring帮你做了,而且人家Spring做成了可配置化,用起来非常简单而且很灵活
补加
1、JDK动态代理
利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制
生成一个实现代理接口的匿名类

在调用具体方法前调用InvokeHandler来处理。

2、CGLIB动态代理
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,把目标类设置为代理累的父类,creatproxy里的setupperclass(target.getclass)。

3、JDK动态代理和CGLIB字节码生成的区别?
1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类。针对于方法

2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,
并覆盖其中方法实现增强
,但是因为采用的是继承,所以该类或方法最好不要声明成final,
对于final类或方法,是无法继承的。

4、CGlib比JDK快?
1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,

在jdk6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,

因为CGLib原理是动态生成被代理类的子类。

2)在jdk6、jdk7、jdk8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLIB代理效率,

只有当进行大量调用的时候,jdk6和jdk7比CGLIB代理效率低一点,但是到jdk8的时候,jdk代理效率高于CGLIB代理,

总之,每一次jdk版本升级,jdk代理效率都得到提升,而CGLIB代理消息确有点跟不上步伐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值