理解
为什要要代理,希望对对象调用方法做增强,例如校验参数,记录日志,统计代码执行效率等。
静态代理即从代码角度来实现代码增强常见的编程设计模式主要是装饰者设计模式。
动态代理即使用反射在代码运行时创建出代理对象。常见的动态代理有jdk动态代理和cglib动态代理。
静态代理demo
静态代理接口:亚飞目标
/**
* @Description: 静态代理接口
* @Author: 马宽
* @Date: 2022/4/3 16:00
*/
public interface StudentStudy {
String aim();
}
静态代理接口实现类:亚飞的目标是考上大学
/**
* @Description: 静态代理接口实现类
* @Author: 马宽
* @Date: 2022/4/3 16:00
*/
public class StudentStudyImpl implements StudentStudy{
@Override
public String aim() {
return "目标上大学";
}
}
但是考上大学是有一定条件的,而且考上大学有很多好处,使用装饰者设计模式来实现,主要是通过包装类把基本的实例对象传入,让装饰者来调用这个实例方法,同时我们也可以让装饰者和实例对象实现同一个接口。这样对于外界来看他们就好像调用同一个方法。
/**
* @Description: 静态代理接口实现类
* @Author: 马宽
* @Date: 2022/4/3 16:00
*/
public class StudentStudyStaticProxy implements StudentStudy{
private StudentStudy studentStudy;
public StudentStudyStaticProxy(StudentStudy studentStudy) {
this.studentStudy=studentStudy;
}
@Override
public String aim() {
System.out.println("好好学习读书");
System.out.println("考试取得好成绩");
String aim = studentStudy.aim();
System.out.println(aim);
System.out.println("找个漂亮女朋友");
return aim;
}
}
测试静态代理
/**
* @Description: 静态代理测试代码
* @Author: 马宽
* @Date: 2022/4/3 16:05
*/
public class StudentStudyStaticProxyApp {
public static void main(String[] args) {
StudentStudy studentStudy=new StudentStudyImpl();
StudentStudyStaticProxy studentStudyStaticProxy=new StudentStudyStaticProxy(studentStudy);
studentStudyStaticProxy.aim();
}
}
你让亚飞的目标更鉴定了
动态代理demo
JDK动态代理
接口:亚飞要参加高考
/**
* @Description: jdk动态代理接口
* @Author: 马宽
* @Date: 2022/4/3 13:29
*/
public interface UserStudy {
String exam();
}
亚飞去考场考试,但是去考场参加考试前他应该先好好学习,我们使用jdk动态代理来增强。
/**
* @Description: jdk动态代理接口
* @Author: 马宽
* @Date: 2022/4/3 13:29
*/
public class UserStudyImpl implements UserStudy {
@Override
public String exam() {
return "去考场参加考试";
}
}
jdk动态代理
UserStudy o = (UserStudy)Proxy.newProxyInstance(类加载器,实现接口,执行器)
/**
* @Description: jdk动态代理,返回代理对象
* @Author: 马宽
* @Date: 2022/4/3 13:33
*/
public class UserStudyJdkProxy {
public static UserStudy getJdkProxyUserService(UserStudy userStudy){
//1.类加载器
ClassLoader classLoader = userStudy.getClass().getClassLoader();
//2.获得所有接口
Class[] interfaces = userStudy.getClass().getInterfaces();
//3.执行原始接口对象方法
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke=null;
System.out.println(method.getName());
if ("exam".equals(method.getName())){
System.out.println("先背书");
//3.注意这里执行的是原始的对象而不是代理出来的对象
invoke = method.invoke(userStudy, args);
System.out.println(invoke);
System.out.println("考试取得好成绩");
}else {
invoke = method.invoke(userStudy, args);
}
return invoke;
}
};
UserStudy o = (UserStudy)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
//返回一个代理对象
return o;
}
}
测试代码
/**
* @Description:
* @Author: 马宽
* @Date: 2022/4/3 13:32
*/
public class App {
public static void main(String[] args) {
UserStudy userStudy =new UserStudyImpl();
UserStudy jdkProxyUserStudy = UserStudyJdkProxy.getJdkProxyUserService(userStudy);
//注意动态代理默认会对所有方法进行增强(toString)
System.out.println("代理出来的对象是"+ jdkProxyUserStudy);
jdkProxyUserStudy.exam();
}
}
你让亚飞在考试前做了充足的准备
cglib动态代理
注:cglib属于spring我们需要在spring环境中进行测试。
cglib的特点在于运行时自动实例化对象,并在调用方法前后你可以自定义的进行增强。
/**
* @Description: cglib动态代理测试类
* @Author: 马宽
* @Date: 2022/4/3 15:47
*/
public class UserStudy {
public String exam(){
return "考试";
}
}
测试代码:
cglib之所以可以产生代理对象是因为把要代理的对象作为了父类。
UserStudy userStudy =new UserStudy();
//1.设置增强器
Enhancer enhancer=new Enhancer();
//2.设置父类
enhancer.setSuperclass(UserStudy.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("读书学习");
Object invoke = method.invoke(userStudy, objects);
System.out.println(invoke);
System.out.println("获得好成绩");
System.out.println("找到漂亮女朋友");
return invoke;
}
});
UserStudy o = (UserStudy)enhancer.create();
o.exam();
其中
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
Object o为代理对象
Object[] objects为原来实例方法参数
Method method为实例中的方法
MethodProxy methodProxy为代理方法
可以看见jdk和cglib代理在执行器中都是执行的原本实例的方法,你在实例执行方法的前后可以尽情的增强。