代理解析(静态代理、动态代理jdk和动态代理cglib)

本文详细介绍了代理模式的概念及其在软件开发中的应用。从静态代理到动态代理(包括JDK动态代理和CGLIB动态代理),通过具体示例展示了如何实现代理模式,以及其背后的原理和技术细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、代理介绍:
开始接触代理是在设计模式动态代理中了解的,大概是这样的:张三喜欢一个女孩,但是她不敢表白怎么办,很简单,他找李四帮他去表白。这里李四就是代理对象,代替张三干活,可以看下面的画面:
在这里插入图片描述
慢慢积累之后,发现很多经典的框架背后都使用了代理的模式,例如Spring的AOP实现原理便是动态代理;常用的ORM模型中mybatis框架实现原理也是动态代理;事务的实现原理反射+动态代理;dubbo的实现中也有动态代理…很多很多,我们可以得出的结论是熟悉代理以及熟悉动态代理的重要性。代理模式是:通过代理控制对目标对象的访问,下面是代理类图:
在这里插入图片描述
二、代理分类
代理分为:静态代理和动态代理;
动态代理分类:jdk动态代理和cglib动态代理。

  **1.静态代理介绍**
         静态代理是有实实在在的代理类存在,并且和目标类实现相同的接口。它的特点是效率高,因为所有的类都是已经编写完		       					                    成的,客户端只需要取得代理对象并且执行即可,同时他可以实现对目标对象中指定的方法进行增强。它的优缺点:

优点:效率高;
缺点:
与目标类实现相同的接口代码冗余;
如果接口发生改变,代理类中的方法也要修改;
代理类服务于一种类型的对象,如果要服务多类型的对象,那么势必要为每种类型的对象都生成代理类。

2.动态代理介绍
动态代理能用很少的代码对一个类的所有方法实现一样的增强效果,但是不能增强其中的某一个方法。与静态代理的硬编
码方式相比,动态代理支持运行时动态生成代理对象这种方式
优点:
在编码时代理逻辑与业务逻辑互相独立;
各不影响,减少侵入,降低耦合。

   **jdk和cglib两种动态代理方式对比:**
*jdk
    目标类和代理类实现了共同的接口;
	    拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方体的内容;
         当客户端用代理对象调用方法的时候,invoke方法执行。
  *cglib
目标类是代理类的父类;
拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体;
使用字节码增强机制创建代理对象的。

三、代理实现过程(coding…)
1.静态代理:
日志:
package com.test.spring.proxy_02proxy;
public class Logger {
public void logger(){
System.out.println(“logging”);
}
}

安全性:
package com.test.spring.proxy_02proxy;
public class Security {
public void security(){
System.out.println(“security…”);
}
}

权限:
package com.test.spring.proxy_02proxy;
public class Privilege {
private String access;
public String getAccess() {
return access;
}
public void setAccess(String access) {
this.access = access;
}
}

接口:
package com.test.spring.proxy_02proxy;
public interface SalaryManager {
public void showSalary();
}

目标类(接口的实现类):
package com.test.spring.proxy_02proxy;
public class SalaryManagerImpl implements SalaryManager{
@Override
public void showSalary() {
System.out.println(“正在查看工资:涨了20W人民币”);
}
}

代理类:
package com.test.spring.proxy_02proxy;
/**

  • 1.导入日志、安全性框架和权限

  • 2.目标对象

  • 3.在代理对象的方法中调用上面的方法

  • */
    public class SalaryManagerProxy implements SalaryManager {
    private Logger logger;
    private Security security;
    private Privilege privilege;
    private SalaryManager targetSalaryManager;

    //利用构造函数赋值
    public SalaryManagerProxy(Logger logger,Security security,Privilege privilege,SalaryManager targetSalaryManager){
    this.logger = logger;
    this.security = security;
    this.privilege = privilege;
    this.targetSalaryManager = targetSalaryManager;
    }

    @Override
    public void showSalary() {
    this.logger.logger();
    this.security.security();
    if(“admin”.equals(this.privilege.getAccess())){
    this.targetSalaryManager.showSalary();
    }else{
    System.out.println(“你没有权限查看!”);
    }
    }
    }

客户端测试类:
package com.test.spring.proxy_02proxy;
import org.junit.Test;
public class SalaryProxyTest {
@Test
public void test(){
Logger logger = new Logger();
Privilege privilege = new Privilege();
privilege.setAccess(“admin”);

	Security security = new Security();
	SalaryManager targetSalaryManager = new SalaryManagerImpl();
	SalaryManagerProxy  salaryManagerProxy = new SalaryManagerProxy(logger, 
                                                                                     security, privilege,  targetSalaryManager);
	salaryManagerProxy.showSalary();
} 

}

2.动态代理:
2.1jdk动态代理
Person实例:
package com.test.spring.proxy_04jdkproxydao;
public class Person {
private Long pid;
private String pname;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
}

接口:
package com.test.spring.proxy_04jdkproxydao;
public interface PersonDao {
public void insertPerson();
public void updatePerson();
public void deletePerson();
}

目标类:(接口的实现类)
package com.test.spring.proxy_04jdkproxydao;
public class PersonDaoImpl implements PersonDao{
@Override
public void insertPerson() {
System.out.println(“insert Person!”);
}
@Override
public void updatePerson() {
System.out.println(“update Person!”);
}
@Override
public void deletePerson() {
System.out.println(“delete Person!”);
}
}

事务:(开启事务,提交事务)
package com.test.spring.proxy_04jdkproxydao;
public class Transaction {
public void beginTransaction(){
System.out.println(“Begin transaction!”);
}
public void commitTransaction(){
System.out.println(“Commit transaction!”);
}
}

拦截器:
package com.test.spring.proxy_04jdkproxydao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonInterceptor implements InvocationHandler{
private Transaction transaction;
private Object target;
public PersonInterceptor(Transaction transaction,Object target){
this.transaction = transaction;
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
		throws Throwable {
	Object obj;
	String methodName = method.getName();
	if("insertPerson".equals(methodName) || "updatePerson".equals(methodName) || 		"deletePerson".equals(methodName)){
		this.transaction.beginTransaction();//开启事务
		obj = method.invoke(target, args);	
		this.transaction.commitTransaction();//提交事务
	}else{
		obj = method.invoke(target, args);
	}		
	return obj;
}

}

客户端测试类:
package com.test.spring.proxy_04jdkproxydao;
import java.lang.reflect.Proxy;
import org.junit.Test;
/**

  • 代理对象的方法:
  • *就是拦截器中invoke方法体的内容
  • *代理对象的方法把目标方法和切面(可以是日志、安全性的检查、权限、事务)就整合在一起了
  • *代理对象的是有jdk的类库生成的
  • */
    public class ProxyDaoTest {
    @Test
    public void test(){
    Transaction transaction = new Transaction();
    PersonDao targerPersonDao = new PersonDaoImpl();
    PersonInterceptor interceptor = new PersonInterceptor(transaction,targerPersonDao);
    //代理对象Proxy,调用的方法是newProxyInstance(loader, interfaces, h)
    PersonDao proxy = (PersonDao) Proxy.newProxyInstance(targerPersonDao.getClass().getClassLoader(),
    targerPersonDao.getClass().getInterfaces(), interceptor);
    proxy.insertPerson();
    }

小总结1:
基于jdk的动态代理需要有实现的接口;
动态代理的核心:是创建了处理器 InvocationHandler实例。在调用目标对象时,会调用代理对象,代理对象中请求目标对象,invoke方法便是调用目标对象的方法生成代理对象的过程,同时增强工作也是在invoke方法中进行的。

2.2cglic动态代理
Person实例:
package com.test.spring.proxy_04jdkproxydao;
public class Person {
private Long pid;
private String pname;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
}

目标类:
package com.test.spring.proxy_04jdkproxydao;
public class PersonDaoImpl{
public void insertPerson() {
System.out.println(“insert Person!”);
}
public void updatePerson() {
System.out.println(“update Person!”);
}
public void deletePerson() {
System.out.println(“delete Person!”);
}
}

事务:(开启事务,提交事务)
package com.test.spring.proxy_04jdkproxydao;
public class Transaction {
public void beginTransaction(){
System.out.println(“Begin transaction!”);
}
public void commitTransaction(){
System.out.println(“Commit transaction!”);
}
}

拦截器:
package com.test.spring.proxy_05cglibproxy;
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 PersonInterceptor implements MethodInterceptor{
private Transaction transaction;
private Object target;
public PersonInterceptor(Transaction transaction,Object target){
this.transaction = transaction;
this.target = target;
}

//创建代理
public Object createProxy(){	
	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(this.target.getClass());//设置目标类为代理类的父类
	enhancer.setCallback(this);//设置拦截器为回调函数
	return enhancer.create();
}	

@Override
public Object intercept(Object arg0, Method method, Object[] arg2, 
		MethodProxy arg3) throws Throwable {
	Object obj;
	
	String methodName = method.getName();
	if("insertPerson".equals(methodName) || "updatePerson".equals(methodName) || "deletePerson".equals(methodName)){
		this.transaction.beginTransaction();//开启事务
		obj = method.invoke(target, arg2);
		this.transaction.commitTransaction();//提交事务
	}else{
		obj = method.invoke(target, arg2);
	}
		
	return obj;

}
}

客户端测试:
package com.test.spring.proxy_05cglibproxy;
import org.junit.Test;
public class ProxyDaoTest {
@Test
public void test(){
Transaction transaction = new Transaction();
PersonDaoImpl targerPersonDao = new PersonDaoImpl();

	PersonInterceptor interceptor = new PersonInterceptor(transaction,targerPersonDao);
	PersonDaoImpl proxy = (PersonDaoImpl) interceptor.createProxy();
	proxy.updatePerson();		
}

}

小总结2:
基于cglib的动态代理是没有实现接口的,它是以目标类作为代理类的父类
cglib动态代理的关键是基于enhancer.setCallback方法,和其中的MethodInterceptor() 方法
在MethodInterceptor实例中重写intercept方法中调用invoke方法设置代理对象,最后通过enhancer.create()创建代理对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值