首页 > 编程语言 > 详细

Spring 静态代理与动态代理

时间:2021-04-24 00:35:07      阅读:24      评论:0      收藏:0      [点我收藏+]

Spring06: 静态与动态代理

什么是代理

了解代理就要自动什么是代理,代理就是代理你办事的“人”,生活中有许多这样的例子,比如婚介所,中介。

代理有什么好处

可以让代码更加纯粹,不需要在主要业务代码中加入其他附庸的功能

公共部分交给了代理,实现了业务的分工

公共业务发生扩展的时候,方便集中管理

静态代理

静态代理由程序员或代码生成工具生成代理类,编译之后生成Class文件,代理关系在编译期就已经绑定,一个代理关系是一个代理类对应一个基础接口。

角色分析

1、抽象角色:一般使用接口或抽象类
2、真实角色:被代理的角色
3、代理角色:代理真实角色,代理真实角色后,我们会做一些附属操作
4、客户角色:访问代理对象的人

技术分享图片

代码实现

1.抽象角色(租房)

package com.znsd.spring.test;

public interface Rent {
	void rentOut();
}

2.真实角色(房东)

package com.znsd.spring.test;

public class Host implements Rent{

	@Override
	public void rentOut() {
		// TODO Auto-generated method stub
		System.out.println("房东要出租房屋");
	}
	
}

3.代理角色(房屋中介)

package com.znsd.spring.test;

public class Agency implements Rent{
	
	Host host = new Host();

	@Override
	public void rentOut() {
		// TODO Auto-generated method stub
		host.rentOut();
        // 房东的额外操作
        fee();
        contract();
        see();
	}
	
	public void fee() {
		System.out.println("收佣金");
	}
	
	public void contract() {
		System.out.println("签合同");
	}
	
	public void see() {
		System.out.println("看房");
	}
	
}

4.客户角色(需要租房的人)

package com.znsd.spring.test;

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class Dynamic {

	@Test
	void test() {
		Rent rent = new Agency();
		rent.rentOut();
	}

}

测试结果:

技术分享图片

动态代理

jdk动态代理

是JDK1.3中引入的特性,核心API是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。它利用反射机制在运行时生成代理类的字节码,为Java平台在带来了运行时动态扩展对象行为的能力。其代理关系是在程序运行时期确定得。(必须使用接口)

接口

package com.znsd.spring.dynamicProxy;

public interface UserService {
	
	
	void add(int id);
	
	void delete(int id);
	
	void update(int id);
	
	void query(int id);

}

被代理类

package com.znsd.spring.dynamicProxy;

public class UserServiceImpl implements UserService{
	
	private int id;
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void add(int id) {
		// TODO Auto-generated method stub
		System.out.println("增加");
	}

	@Override
	public void delete(int id) {
		// TODO Auto-generated method stub
		System.out.println("删除");
	}

	@Override
	public void update(int id) {
		// TODO Auto-generated method stub
		System.out.println("修改");
	}

	@Override
	public void query(int id) {
		// TODO Auto-generated method stub
		System.out.println("查询");
	}

	
}

增强类

package com.znsd.spring.dynamicProxy;

public class Extend {
	
	public static void log(String msg,int id) {
		System.out.println(msg+"了id为:"+id+"的用户");
	}
}

生成被代理类

package com.znsd.spring.dynamicProxy;

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

public class ProxyInvocationHandler implements InvocationHandler{
	
	private Object object;
	
	
	public ProxyInvocationHandler() {
		super();
	}

	public ProxyInvocationHandler(Object object) {
		super();
		this.object = object;
	}

	public void setObject(Object object) {
		this.object = object;
	}
	
	public Object getProxy() {
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		Object rusObject = method.invoke(object, args);
		Extend.log(method.getName(), (int)args[0]);
		return rusObject;
	}
	
}

代理程序控制器

package com.znsd.spring.dynamicProxy;

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

public class ProxyInvocationHandler implements InvocationHandler{
	
	private Object object;
	
	
	public ProxyInvocationHandler() {
		super();
	}

	public ProxyInvocationHandler(Object object) {
		super();
		this.object = object;
	}

	public void setObject(Object object) {
		this.object = object;
	}
	
	public Object getProxy() { // 生成被代理类
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), 			this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// TODO Auto-generated method stub
		Object rusObject = method.invoke(object, args);
		Extend.log(method.getName(), (int)args[0]);
		return rusObject;
	}
	
}

使用测试

package com.znsd.spring.dynamicProxy;

public class Main {
	public static void main(String[] args) {
		
		ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(new UserServiceImpl());
		
		UserService userService  = (UserService)proxyInvocationHandler.getProxy();
		userService.add(1);
		userService.delete(2);
		userService.update(3);
		userService.query(4);
	}
}

技术分享图片

cglib动态代理

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。

CGLIB动态代理的实现机制是生成目标类的子类,在子类中调用父类的方法从而实现对目标父类方法的增强。

被代理类:

package com.znsd.spring.cglib;

public class Tatger {

	public void save() {
		System.out.println("正在保存");
	}
}

代理程序控制类:

package com.znsd.spring.cglib;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class MyMethodInterceptor implements MethodInterceptor {

	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
		// TODO Auto-generated method stub
		MyLog.befor();
		Object obj = arg3.invokeSuper(arg0, arg2);
		MyLog.end();
		return obj;
	}
	
}

增强类:

package com.znsd.spring.cglib;

import java.io.Console;

public class MyLog {
	
	public static void befor() {
		System.out.println("前置Log");
	}
	
	public static void end() {
		System.out.println("后置Log");
	}

}

生成代理类:

package com.znsd.spring.cglib;

import org.springframework.cglib.proxy.Enhancer;

public class CglibProxy {
	
	public static Object getProxy(Class<?> clazz) {
		
		 // 创建动态代理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(clazz);
        // 设置方法拦截器
        enhancer.setCallback(new MyMethodInterceptor());
        return enhancer.create();
		
	}

}

测试:

package com.znsd.spring.cglib;

import static org.junit.jupiter.api.Assertions.*;

class Test {

	@org.junit.jupiter.api.Test
	void test() {
		Tatger tatger = (Tatger) CglibProxy.getProxy(Tatger.class);
		tatger.save();
	}

}

技术分享图片

两种动态代理的区别

1、Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理

2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理

什么时候用cglib什么时候用jdk动态代理?

1、目标对象生成了接口 默认用JDK动态代理

2、如果目标对象使用了接口,可以强制使用cglib

3、如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换

JDK动态代理和cglib字节码生成的区别?

1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类

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

Cglib比JDK快?

1、cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高

2、在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率

3、只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib

4、Cglib不能对声明final的方法进行代理,因为cglib是动态生成代理对象,final关键字修饰的类不可变只能被引用不能被修改

Spring如何选择是用JDK还是cglib?

1、当bean实现接口时,会用JDK代理模式

2、当bean没有实现接口,用cglib实现

3、可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/

Spring 静态代理与动态代理

原文:https://www.cnblogs.com/liuzhihui021221/p/14695748.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!