代理模式定义
代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。
引用网上代理模式结构图
代理的分类
静态代理:
代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。
JDK代理:
JDK动态代理只能对实现了接口的类生成代理,而不能针对类- CGLIB代理:
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
代码实现
整体代码目录结构
github:https://github.com/xzsyr/learn/tree/master/xzsyr-proxy
静态代理
ICount.java
package com.xzsyr.statiz.proxy;
/**
* Title: ICount.java Description: 账号接口
*
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:10
*/
public interface ICount {
/**
* @discription 查询账号列表
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:54
*/
public void queryCount();
}
CountImpl.java
/**
* Title: CountImpl.java
* Description: 账号信息实现类
* @author jizhuang.wang
* @created 2018年5月10日 下午4:37:40
*/
public class CountImpl implements ICount{
/**
* @discription 在此输入一句话描述作用
* @author jizhuang.wang
* @created 2018年5月10日 下午4:37:54
* @see com.xzsyr.statiz.proxy.ICount#queryCount()
*/
@Override
public void queryCount() {
System.out.println("我是queryCount方法.");
}
}
CountProxyImpl.java
package com.xzsyr.statiz.proxy;
/**
* Title: CountProxyImpl.java
* Description: 账号信息代理实现类
* @author jizhuang.wang
* @created 2018年5月10日 下午4:39:37
*/
public class CountProxyImpl implements ICount{
private CountImpl count;
/**
* @discription 账号信息查询
* @author jizhuang.wang
* @created 2018年5月10日 下午4:40:31
* @see com.xzsyr.statiz.proxy.ICount#queryCount()
*/
@Override
public void queryCount() {
System.out.println("事务处理前.....");
count.queryCount();
System.out.println("事务处理后.....");
}
public CountProxyImpl(CountImpl count) {
super();
this.count = count;
}
}
StaticMain.java
package com.xzsyr.statiz.proxy;
/**
* @author Stronger
*
*/
public class StaticMain {
public static void main(String[] args) {
CountImpl c = new CountImpl();
CountProxyImpl p = new CountProxyImpl(c);
p.queryCount();
}
}
静态代理执行结果
事务处理前…..
我是queryCount方法.
事务处理后…..
- JDK代理
ICount.java
/**
* Title: ICount.java Description: 账号接口
* 目标类接口
* 目标类和动态生成的代理对象都实现的接口
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:10
*/
public interface ICount {
/**
* @discription 查询账号列表
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:54
*/
public void queryCount();
}
CountImpl.java
/**
* @author Stronger
*
*/
public class CountImpl implements ICount{
/* (non-Javadoc)
* @see com.xzsyr.jdkdy.proxy.ICount#queryCount()
*/
@Override
public void queryCount() {
System.out.println("我是queryCount方法");
}
}
CountImpl.java
package com.xzsyr.jdkdy.proxy;
/**
* @author jizhuang.wang
*
*/
public class CountImpl implements ICount{
/* (non-Javadoc)
* @see com.xzsyr.jdkdy.proxy.ICount#queryCount()
*/
@Override
public void queryCount() {
System.out.println("我是queryCount方法");
}
}
MyInvocationHandler.java
package com.xzsyr.jdkdy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Title: MyInvocationHandler.java
* Description: JDK动态代理类
* 代理对象的拦截器
* @author jizhuang.wang
* @created 2018年5月10日 下午5:00:41
*/
public class MyInvocationHandler implements InvocationHandler{
private CountImpl countImpl;
/**
* 构造函数
* @param countImpl 被代理对象
*/
public MyInvocationHandler(CountImpl countImpl) {
// super();
this.countImpl = countImpl;
}
/**
* @discription 在此输入一句话描述作用
* @author jizhuang.wang
* @created 2018年5月10日 下午5:01:22
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("事务处理前。。。。");
method.invoke(countImpl, args);
System.out.println("事务处理后。。。。");
return null;
}
}
JDKMain.java
package com.xzsyr.jdkdy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* @author jizhuang.wang
*
*/
public class JDKMain {
public static void main(String[] args) {
CountImpl count = new CountImpl();
count.queryCount();
System.out.println("==========================================");
/**
* 以下代码会生成一个$Proxy对象,该对象实现了ICount接口,具体的方法体就是InvocationHandler里面的invoke方法。
*/
InvocationHandler hander = new MyInvocationHandler(count);
ICount proxyInstance = (ICount) Proxy.newProxyInstance(count.getClass().getClassLoader(), count.getClass().getInterfaces(), hander);
proxyInstance.queryCount();
}
}
JDK动态代理执行结果
我是queryCount方法
事务处理前。。。。
我是queryCount方法
事务处理后。。。。
- CGLib代理
ICount.java
package com.xzsyr.cglibdy.proxy;
/**
* Title: ICount.java Description: 账号接口
*
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:10
*/
public class ICount {
/**
* @discription 查询账号列表
* @author jizhuang.wang
* @created 2018年5月10日 下午4:36:54
*/
public void queryCount() {
System.out.println("账户类查询方法");
}
}
CountImpl.java
package com.xzsyr.cglibdy.proxy;
/**
* @author jizhuang.wang
*
*/
public class CountImpl {
public void quryCount(){
System.out.println("查询querycount方法");
}
}
CountImplCglib.java
package com.xzsyr.cglibdy.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author jizhuang.wang
*
*/
public class CountImplCglib implements MethodInterceptor{
///业务类对象,供代理方法中进行真正的业务方法调用
private Object target;
//相当于JDK动态代理中的绑定
public Object getInstance(Object target){
//创建加强器,用来创建动态代理类
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
// 实现回调方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("预处理——————");
proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
System.out.println("调用后操作——————");
return null;
}
}
CGLIBMain.java
package com.xzsyr.cglibdy.proxy;
/**
* @author jizhuang.wang
*
*/
public class CGLIBMain {
public static void main(String[] args) {
CountImpl c = new CountImpl();
CountImplCglib cglib = new CountImplCglib();
CountImpl ccglib = (CountImpl) cglib.getInstance(c);
ccglib.quryCount();
}
}
CGLIB动态代理执行结果
预处理——————
查询querycount方法
调用后操作——————
而AOP,是通过动态代理实现的。
Spring在选择用JDK还是CGLiB的依据
(1)当Bean实现接口时,Spring就会用JDK的动态代理 (2)当Bean没有实现接口时,Spring使用CGlib是实现 (3)可以强制使用CGlib (在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
CGlib与JDK比较(参考)
(1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
(2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
关于cglib代理编码依赖包说明
cglib必须依赖一下jar:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>5.0.4</version>
</dependency>
使用CGlib出现java.lang.NoClassDefFoundError: org/objectweb/asm/Type异常
报错显示有找不到的类,上网查了以下知道了很多java字节码操作和分析的第三方类库都引用了asm.jar文件,由于工程不是Maven管理的,无法解决以来传递问题,所以要手动引入asm.jar文件。把asm.jar文件添加到项目路径类,运行,然后就正常了。
非maven项目
cglib.jar下载
asm.jar下载
https://github.com/xzsyr/craft-cloud/tree/master/repo