- 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理
对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的 功能操作,即扩展目标对象的功能。- 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
- 代理模式有不同的形式, 主要有三种
静态代理、动态代理(也叫JDK代理或接口代 理)和Cglib代理(可以在内存动态的创建对象,而不需要实现接口, 他是属于 动态代理的范畴)
- 优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展
- 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类
- 一旦接口增加方法,目标对象与代理对象都要维护

接口
public interface ITeacherDao {
void teach();
}
实现类
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("老师上课中………………");
}
}
代理类
public class TeacherDaoProxy implements ITeacherDao{
/**
* 目标对象,通过接口来聚合
*/
private ITeacherDao target;
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
System.out.println("代课老师上课中…………");
target.teach();
System.out.println("代课老师上课结束………………");
}
}
测试类
public class Client {
public static void main(String[] args) {
TeacherDao teacherDao =new TeacherDao();
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
teacherDaoProxy.teach();
}
}
基本概念:
AOP:面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得
业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
AOP 底层使用动态代理
(1)有两种情况动态代理
第一种有接口情况,使用 JDK 动态代理
⚫ 创建接口实现类代理对象,增强类的方法
第二种没有接口情况,使用 CGLIB 动态代理
⚫ 创建子类的代理对象,增强类的方法
static Object
newProxyInstance(ClassLoader loader, 类>[] interfaces, InvocationHandler h)
返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序
第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

接口
public interface ITeacherDao {
void teach();
void sayHello(String name);
}
接口实现
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("老师正在上授课中………………");
}
@Override
public void sayHello(String name) {
System.out.println(name+"我爱你");
}
}
代理类
public class ProxyFactory {
//维护一个目标对象
private Object target;
//构造,初始化目标对象
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象生成一个代理对象
public Object getProxyInstance(){
/*
* newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
1、ClassLoader loader 指定当前目标对象使用的类加载器,获取加载器的方法固定
2、Class>[] interfaces 目标对象实现接口类型,使用泛型方法确认类型
3、InvocationHandler 事情处理,执行目标对象方法时,会触发事情处理方法,会把当前执行的目标对象方法作为参数传入
*/
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理开始……");
Object invoke = method.invoke(target, args);
return invoke;
}
});
}
}
测试
public class Client {
public static void main(String[] args) {
//目标对象
ITeacherDao target = new TeacherDao();
//给目标对象创建代理对象
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
proxyInstance.teach();
proxyInstance.sayHello("老王");
}
}
。
public class FeignProxyInvocationHandler implements InvocationHandler {
/**
* feign接口
*/
private Object feignClient;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(feignClient, args);
//RespResult是我们的通用返回类型
if (invoke instanceof RespResult) {
RespResult result = (RespResult) invoke;
//这里是判断是否返回成功,并且结果不是null
AssertUtil.assertTrue(CommonUtils.isRespSuccess(result) && result.getData() != null, result.getCode(), result.getMessage());
return result;
}
return invoke;
}
/**
* 实例化代理对象
* 这里的this指上面的invoke方法
* @param delegate
* @return
*/
public Object buildProxy(Object delegate) {
this.feignClient = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
public static Object getProxy(Object feignClient) {
return new FeignProxyInvocationHandler().buildProxy(feignClient);
}
}
在其他地方使用:
比如某实现类
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper,UserInfo> implements UserInfoService,InitializingBean{
@Resource
private SmsFeignClient smsFeignClient;
//………………业务代码………………
@override
public void afterPropertiesSet() throws Exception{
smsFeignClient = (SmsFeignClient)FeignProxyInvocationHandler.getProxy(smsFeignClient);
}
}
好处:方法调用处不必考虑空指针、调用失败等(如果其它异常也可以自己在代理类的invoke方法中自己统一加)
- 静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只
是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现 代理-这就是Cglib代理- Cglib代理也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功 能扩展, 有些书也将Cglib代理归属到动态代理。
- Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接 口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截
- 在AOP编程中如何选择代理模式:
- 目标对象需要实现接口,用JDK代理
- 目标对象不需要实现接口,用Cglib代理 5) Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类

被代理类
public class TeacherDao {
public void teach(){
System.out.println("老师授课中…………");
}
public String teach2(){
return "老师授课中…………";
}
}
代理类
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
//构造器
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象,是target的代理对象
public Object getProxyInstance(){
//1.创建工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(target.getClass());
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类,即代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理模式开始…………");
Object invoke = method.invoke(target, args);
System.out.println("cglib代理模式结束…………");
return invoke;
}
}
测试类
public class Client {
public static void main(String[] args) {
//目标对象
TeacherDao teacherDao = new TeacherDao();
//将目标对象传递给代理对象
ProxyFactory proxyFactory = new ProxyFactory(teacherDao);
TeacherDao proxyInstance = (TeacherDao)proxyFactory.getProxyInstance();
proxyInstance.teach();
String s = proxyInstance.teach2();
System.out.println(s);
}
}