目录
一、引言:
1.1 引言
代理,我们在生活中也随处可见,例如厂家面向客户,无需提供专门的售前和售后服务团队,只需要专注于自己的核心业务一一生产即可,而是将各个工厂的售前咨询和售后服务交由“代理”一个团队完成,提高了团队功能的复用性,代理设计的模式的优点:将通用性的工作交给代理对象完成,将代理对象只需专注于自己的核心部分即可,而代理又分为:“静态代理”和“动态代理”,由于静态代理的不灵活性,所以我们重点了解、讲解“动态代理”的实现
1.2 实例准备工作
- 首先我们需要创建一个maven项目,使用maven工程创建模板创建即可,此处的具体步骤略。
- 添加spring-context依赖
- 创建StudentDao接口,接口中定义了三个方法(添加、删除、查询)
- 创建StudentDao的实现类StudentDaoImpl,作为被代理类,在被代理类中实现StudentDao接口中的方法
StudentDao接口 | StudentDaoImpl |
package com.xgsm.ioc.Dao; import com.xgsm.ioc.entity.Student; import java.util.List; public interface StudentDao { public int insertStu(); public int deleteStu(); public List<Student> selectStu(); } | package com.xgsm.ioc.ServiceImp; import com.xgsm.ioc.Dao.StudentDao; import com.xgsm.ioc.entity.Student; import java.util.List; public class StudentDaoImpl implements StudentDao{ @Override public int insertStu() { System.out.println("Student添加方法"); return 0; } @Override public int deleteStu() { System.out.println("Student删除方法"); return 0; } @Override public List<Student> selectStu() { System.out.println("查询所有学生"); return null; } } |
二、动态代理:
2.1 jdk动态代理简介
Jdk动态代理的实现简单的来说,就是通过被代理对象实现的接口产生其代理对象的
2.2 JDK动态代理实现的步骤
- 创建一个类,实现InvocationHandle接口,重写invoke方法
package com.xgsm.ioc.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkDynamicProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return 0;
}
2、在类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象
package com.xgsm.ioc.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkDynamicProxy implements InvocationHandler {
//被代理对象
private Object obj;
public JdkDynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return 0;
}
3、定义一个getProxy()方法,在方法中获取被代理对象的类加载器、获取被代理代理对象实现的接口,通过被代理对象的类加载器以及实现的接口创建并返回代理对象;在产生代理对象的时候newProxyInstance()方法中有三个参数,分别是:
- 第一个参数:被代理对象的类加载器
- 第二个参数:被代理对象实现的接口
- 第三个参数:使用产生代理对象调用方法时,用于拦截方法执行的处理器InvocationHandler
package com.xgsm.ioc.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JdkDynamicProxy implements InvocationHandler { //被代理对象 private Object obj; public JdkDynamicProxy(Object obj) { this.obj = obj; } //产生代理对象,返回代理对象 public Object getProxy() { //获取被代理对象的类加载器 ClassLoader loader = obj.getClass().getClassLoader(); //获取被代理对象的类实现的接口 Class<?>[] interfaces = obj.getClass().getInterfaces(); //产生代理对象(通过被代理对象的类加载器及实现的接口) Object proxy = Proxy.newProxyInstance(loader, interfaces, this); return proxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return 0; } }
4、重写invoke()方法,重写方法时,在JdkDynamicProxy类中新增两个方法,模拟“开启事务”、“提交事务”功能,分别在调用方法前后执行,在invoke()方法中通过反射执行method方法(method在测试类会有说明)
package com.xgsm.ioc.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Description: Spring-Ioc-demo02 * Created by WuHuaSen . * Created Date: 2022/4/14 14:10 * Version: V1.0 */ public class JdkDynamicProxy implements InvocationHandler { //被代理对象 private Object obj; public JdkDynamicProxy(Object obj) { this.obj = obj; } //产生代理对象,返回代理对象 public Object getProxy() { //获取被代理对象的类加载器 ClassLoader loader = obj.getClass().getClassLoader(); //获取被代理对象的类实现的接口 Class<?>[] interfaces = obj.getClass().getInterfaces(); //产生代理对象(通过被代理对象的类加载器及实现的接口) Object proxy = Proxy.newProxyInstance(loader, interfaces, this); return proxy; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { init(); Object returnValue =method.invoke(obj); commit(); return returnValue; } public void init() { System.out.println("开启事务"); } public void commit() { System.out.println("提交事务"); } }
2.3 JDK动态代理测试
创建被代理对象并传递到代理类中,产生代理对象,使用代理对象调用方法
package com.xgsm.ioc.Test;
import com.xgsm.ioc.Dao.StudentDao;
import com.xgsm.ioc.Proxy.JdkDynamicProxy;
import com.xgsm.ioc.ServiceImp.StudentDaoImpl;
/**
* Description: Spring-Ioc-demo02
* Created by WuHuaSen .
* Created Date: 2022/4/14 14:17
* Version: V1.0
*/
public class jdkDynamicProTest {
public static void main(String[] args) {
//创建被代理对象
StudentDaoImpl studentDao = new StudentDaoImpl();
//创建动态代理对象传递到代理类中
JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(studentDao);
//proxy就是产生的代理对象,可以强转成被代理对象实现的接口
StudentDao proxy =(StudentDao) jdkDynamicProxy.getProxy();
proxy.insertStu();
}
}
使用代理对象调用方法,并不会执行调用的方法,而是进入到创建的代理对象指定的invocationHandle类中的invoke()方法中,调用方法作为一个method方法,传递给invoke
2.4 Jdk动态代理测试:
三、Cglib动态代理:
3.1 Cglib动态代理简介
由于Jdk动态代理是通过被代理对象实现的接口来创建代理对象的,因此jdk动态代理只能代理实现了接口的类的对象,如果一个类没有实现任何接口,就可以使用Cglib动态代理,Cglib动态代理是通过创建被代理类的子类来创建类的子类来创建代理对象的,因此即使没有实现任何接口的类也可以通过Cglib产生代理对象
3.2 Cglib动态代理实现的步骤
1、添加Cglib依赖(可以在maven仓库中进行搜索:https://mvnrepository.com)版本没有要求,也可以直接在下面代码中直接赋值添加到pom.xml文件中
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
2、创建一个类CglibDynamicProxy并实现MethodInterceptor接口,同时实现接口中的方法
package com.xgsm.ioc.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibDynamicProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return null;
}
}
3、在类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象
package com.xgsm.ioc.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Description: Spring-Ioc-demo02
* Created by WuHuaSen .
* Created Date: 2022/4/14 14:25
* Version: V1.0
*/
public class CglibDynamicProxy implements MethodInterceptor {
private Object object;
public CglibDynamicProxy(Object object) {
this.object = object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return null;
}
}
4、定义getProxy方法来创建并返回代理对象,代理对象是通过创建并代理类的子类来创建的 ,使用Enhancer来创建对象,并进行setCallBack进行回调,使用create()创建Proxy并返回给getProxy,重写intercept()方法,重写方法时,在CglibDynamicProxy类中新增两个方法,模拟“开启事务”、“提交事务”功能,分别在调用方法前后执行,在intercept()方法中通过反射调用被代理类的方法
package com.xgsm.ioc.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Description: Spring-Ioc-demo02
* Created by WuHuaSen .
* Created Date: 2022/4/14 14:25
* Version: V1.0
*/
public class CglibDynamicProxy implements MethodInterceptor {
private Object object;
public CglibDynamicProxy(Object object) {
this.object = object;
}
public Object getProxy(){
//使用Enhancer创建对象
Enhancer enhancer = new Enhancer();
//制定父类
enhancer.setSuperclass(object.getClass());
//回调
enhancer.setCallback(this);
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
init();
Object returnValue = method.invoke(object,objects);
commit();
return returnValue;
}
public void init() {
System.out.println("开启事务");
}
public void commit() {
System.out.println("提交事务");
}
}
2.3 Cglib动态代理测试类
在测试类中创建被代理对象,通过Cglib动态代理创建代理对象,通过代理对象调用方法
package com.xgsm.ioc.Test;
import com.xgsm.ioc.Proxy.CglibDynamicProxy;
import com.xgsm.ioc.ServiceImp.StudentDaoImpl;
public class CglibDynamicProxyTest {
public static void main(String[] args) {
//创建动态代理对象
StudentDaoImpl studentDao = new StudentDaoImpl();
//通过Cglib动态代理类创建代理对象
CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(studentDao);
//代理对象实际上是被代理对象的子类,因此代理对象可以直接强转为代理类类型
StudentDaoImpl proxy = (StudentDaoImpl) cglibDynamicProxy.getProxy();
proxy.insertStu();
}
}
使用对象调用方法,实际上并没有调用执行这个方法,而是执行了代理类中的intercept方法,将当前调用方法以及方法中参数传递给intercept方法
2.4 Cglib动态代理测试:
四、动态代理总结:
4.1 动态代理的好处:
java的动态代理的优势在于实现无侵入式的代码扩展,也就是方法的增强;能够让我们可以在不用修改的源码情况下,增强一些方法;在方法的前后你可以做你任何想做的事情(甚至不去执行这个方法就可以)。