原始静态代理
public interface Singer {
void sing();
}
public class Star implements Singer {
@Override
public void sing() {
System.out.println("now singing~~");
}
}
public class StarAgent implements Singer {
Star s;
public StarAgent(Star s) {
this.s = s;
}
@Override
public void sing() {
System.out.println("this is for vip");
s.sing();
}
}
public class StaticProxy {
public static void main(String[] args) {
Singer singer = new StarAgent(new Star());
singer.sing();
}
}
this is for vip
now singing~~
JDK代理
interface JdkProxyInterface {
void gotoSchool();
void gotoWork();
void oneDay();
void oneDayFinal();
}
public class JdkConcreteClass implements JdkProxyInterface{
@Override
public void gotoSchool() {
System.out.println("gotoSchool..");
}
@Override
public void gotoWork() {
System.out.println("gotoWork..");
}
@Override
public void oneDay() {
gotoSchool();
gotoWork();
}
@Override
public void oneDayFinal() {
gotoSchool();
gotoWork();
}
}
/**
* InvocationHandler 的一个实现,实际上处理代理的逻辑在这里
*/
public class JdkMyInvocationHandler implements InvocationHandler {
JdkProxyInterface jdkProxyInterface;
public JdkMyInvocationHandler(JdkProxyInterface jdkProxyInterface) {
this.jdkProxyInterface = jdkProxyInterface;
}
private void aopMethod() {
System.out.println("before AOP...");
}
//继承方法,代理时实际执行的犯法,如果要实现原方法,则需要调用method.invoke(javaProxy, args),
// 这里还调用了一个aopMethod(),可以类比于Spring中的切面before注解。
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
this.aopMethod();
return method.invoke(jdkProxyInterface, args);
}
}
public class JdkJavaProxyTest {
public static void main(String[] args) {
JdkConcreteClass jdkConcreteClass = new JdkConcreteClass();
JdkProxyInterface newProxyInstanceClass =
(JdkProxyInterface) Proxy.newProxyInstance(
JdkJavaProxyTest.class.getClassLoader(),
new Class[]{JdkProxyInterface.class},
new JdkMyInvocationHandler(jdkConcreteClass)
);
newProxyInstanceClass.oneDay();
// newProxyInstanceClass.oneDayFinal();
}
}
before AOP...
gotoSchool..
gotoWork..
CGLIB代理
public class CglibTestSon {
public CglibTestSon() {
}
public void gotoHome() {
System.out.println("gotoHome..");
}
public void gotoSchool() {
System.out.println("gotoSchool..");
}
public void oneday() {
gotoHome();
gotoSchool();
}
public final void onedayFinal() {
gotoHome();
gotoSchool();
}
}
/**
* 可以类比于jdk动态代理中的InvocationHandler,
* 实际上被代理后重要的类,实际上后续执行的就是intercept里的方法,
* 如果需要执行原来的方法,则调用 method.invoke(s, args);
* 这里也加了一个aopMethod();
*/
public class CglibInvoker implements MethodInterceptor {
CglibTestSon cglibTestSon;
public CglibInvoker(CglibTestSon cglibTestSon) {
this.cglibTestSon = cglibTestSon;
}
private void aopMethod() {
System.out.println("before AOP...");
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
aopMethod();
Object invoke = method.invoke(cglibTestSon, args);
return invoke;
}
}
public class CglibProxyTest {
public static void main(String[] args) {
CglibTestSon CglibTestSon = new CglibTestSon();
Enhancer enhancer = new Enhancer();
Callback s = new CglibInvoker(CglibTestSon);
enhancer.setSuperclass(CglibTestSon.class);
Callback callbacks[] = new Callback[] { s };
enhancer.setCallbacks(callbacks);
CglibTestSon CglibTestSon2 = (CglibTestSon) enhancer.create();
// CglibTestSon2.gotoHome();
// CglibTestSon2.gotoSchool();
// 这里可以看到这个类以及被代理,在执行方法前会执行aopMethod()。这里需要注意的是oneDay()方法和onedayFinal()的区别。
// onedayFinal的方法aopMethod执行2次,oneDay的aopMethod执行1次 ,注意这里和jdk的代理的区别
CglibTestSon2.oneday();
CglibTestSon2.onedayFinal();
}
}
before AOP...
gotoHome..
gotoSchool..
before AOP...
gotoHome..
before AOP...
gotoSchool..
| 名称 | 备注 |
|---|---|
| 静态代理 | 简单,代理模式,是动态代理的理论基础。常见使用在代理模式 |
| jdk动态代理 | 需要有顶层接口才能使用,但是在只有顶层接口的时候也可以使用,常见是mybatis的mapper文件是代理。使用反射完成。使用了动态生成字节码技术。 |
| cglib动态代理 | 可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。 |
jdk底层实现
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); // proxyName 为类名,interfaces为顶层接口Class
//如果需要看,可以将字节码写入文件进行观察
File file = new File("D:/testProxy/Ddd.class");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(bs);
fileOutputStream.flush();
fileOutputStream.close();
自己观察可以从Proxy.newProxyInstance( ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler)进行观察,简单来看就是先生成新的class文件,然后加载到jvm中,然后使用反射,先用class取得他的构造方法,然后使用构造方法反射得到他的一个实例。
标红的是最复杂的。然后cglib的实现原理基本一致,唯一的区别在于生成新的class文件方式和结果不一样。
cglib 底层实现
直接上最终生成字节码的代码。需要注意的是这里要想执行这句话,必须在实现cglib动态代理的代码之后,否则取不到DefaultGeneratorStrategy的实例。
byte[] bs = DefaultGeneratorStrategy.INSTANCE.generate(enhancer);
FileOutputStream fileOutputStream = new FileOutputStream("D:/testProxy/Cc.class");
fileOutputStream.write(bs);
fileOutputStream.flush();
fileOutputStream.close();
跟踪enhancer.create(); 这个代码可以看具体怎么生成字节码,怎么将字节码转化为类。过程基本雷同于jdk,主要区别在于生成字节码的区别。