静态代理动态代理
Posted alimayun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态代理动态代理相关的知识,希望对你有一定的参考价值。
代理模式最大的优势就是能够解耦,在spring中也是广泛使用。spring中一个重要的特性就是aop,aop是个啥东西呢?其实很简单,比如现在有个业务方法,那这个业务方法很重要,涉及到非常重要的业务数据,那对于广大企业应用来说,为了以后能够及时的定位问题,需要记录相关入参以及出参到日志表。
但是对于企业应用来说,需要记录日志的地方应该是蛮多的,如果每个方法中都手动的去写这些记录日志的东西,就会特别的冗余,那使用代理模式就可以解决。
一、静态代理
1、User接口
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下没有难敲的代码!
*/
public interface User {
/*
* 业务逻辑接口
*/
public void work(String workName);
}
2、UserImpl实现类
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下没有难敲的代码!
*/
public class UserImpl implements User {
/*
* 实际业务逻辑实现方法
*/
@Override
public void work(String workName) {
System.out.println("我是做" + workName + "的");
}
}
3、代理类
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下没有难敲的代码!
* 此类为代理类,并且实现业务逻辑类接口,接收一个实际业务处理对象
*/
public class ProxyUser implements User {
private User user;
public ProxyUser(User user) {
this.user = user;
}
@Override
public void work(String workName) {
/*
* 调用实际业务逻辑处理前可以定制化一些功能
*/
System.out.println("工作前先放松放松=============");
/*
* 调用实际业务逻辑处理方法
*/
user.work(workName);
/*
* 调用实际业务逻辑处理后也可以定制一些功能
*/
System.out.println("工作后还是要放松放松=============");
}
}
4、StaticProxyDemo
package com.ty.staticProxy;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下没有难敲的代码!
*/
public class StaticProxyDemo {
public static void main(String[] args) {
User proxyUser = new ProxyUser(new UserImpl());
proxyUser.work("java开发");
}
}
运行结果:
工作前先放松放松=============
我是做java开发的
工作后还是要放松放松=============
二、动态代理
在java中,实现动态代理主要有两种方式,一种是jdk动态代理,一种是cglib
1、jdk动态代理
User以及UserImpl跟上面一致
a、UserDynamicProxy
package com.ty.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下没有难敲的代码!
*/
public class UserDynamicProxy implements InvocationHandler {
private User user;
public UserDynamicProxy(User user) {
this.user = user;
}
/*
* jdk动态代理基于接口,其中proxy好像没啥卵用、method代表当前被代理对象的实际调用方法、args则代表方法参数
* 由invoke方法对被代理对象进行相关的增强
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("工作前放松放松========");
method.invoke(user, args);
System.out.println("工作后也要放松放松===========");
return null;
}
}
b、DynamicProxyDemo
package com.ty.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下没有难敲的代码!
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
User user = new UserImpl();
InvocationHandler h = new UserDynamicProxy(user);
/*
* 使用Proxy的静态方法是生成代理类的核心。
* 一共有三个参数:
* 1、第一个参数是被代理类的类加载器,通过此类加载器将代理类加载入jvm中;
* 2、第二个参数则是被代理类所实现的所有接口,需要所有的接口的目的是创建新的代理类实现被代理类的所有接口,保证被代理类所有方法都能够
* 被代理。其实代理的核心就是新创建一个类并实例化对象,去集成被代理对象所有功能的同时,再加入某些特性化的功能;
* 3、第三个参数则是真正的扩展,使用动态代理的主要目的就是能够对原方法进行扩展,尤其是对于大部分方法都具有的重复方法(例如记录日志),
* 可以理解为面向切面编程中的增强.
*/
User proxy = (User) Proxy.newProxyInstance(User.class.getClassLoader(), user.getClass().getInterfaces(), h);
/*
* 在调用生成的代理类对象后,调用原方法后,该method对象以及参数等会被传入到InvocationHandler的invoke方法中,由InvocationHandler的
* invoke方法对被代理类对象进行增强。
*/
proxy.work("敲代码");
proxy.eat("吃大餐");
}
}
2、cglib代理
jdk动态代理的缺点就是必须基于接口,没有接口就无法实现代理,而cglib则是使用继承的方式去生成代理类,使用范围更广
a、添加cglib.jar、asm.jar(注意jar包版本)
使用cglib前必须进行导包,并且版本如果过低会导致报错
b、UserImpl(使不使用接口都可以)
package com.ty.dynamic.cglib;
/**
* @author Taoyong
* @date 2018年7月1日
* 天下没有难敲的代码!
*/
public class UserImpl {
/*
* 实际业务逻辑实现方法
*/
public void work(String workName) {
System.out.println("我是做" + workName + "的");
}
}
c、CglibDynamicProxy
package com.ty.dynamic.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下没有难敲的代码!
*/
public class CglibDynamicProxy implements MethodInterceptor {
/*
* 实际的增强
*/
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("这是前处理==============");
methodProxy.invokeSuper(obj, objects);
System.out.println("这是前处理==============");
return null;
}
}
d、CglibProxyDemo
package com.ty.dynamic.cglib;
import net.sf.cglib.proxy.Enhancer;
/**
* @author Taoyong
* @date 2018年7月2日
* 天下没有难敲的代码!
*/
public class CglibProxyDemo {
public static void main(String[] args) {
/*
* 创建字节码增强器
*/
Enhancer enhancer = new Enhancer();
/*
* 被代理类设置为字节码增强器父类,cglib使用的是继承方式去创建代理类
*/
enhancer.setSuperclass(UserImpl.class);
/*
* 设置字节码增强器回调方法
*/
enhancer.setCallback(new CglibDynamicProxy());
/*
* 创建代理实例
*/
UserImpl userImpl = (UserImpl) enhancer.create();
userImpl.work("敲代码");
}
}
以上是关于静态代理动态代理的主要内容,如果未能解决你的问题,请参考以下文章