AOP的设计思想
作者:bin一、静态代理:
静态代理就是实现一个「新类」他和「原类」实现同一个接口,使用时替换「原类」以达到增强的效果
package com.zengbingo.proxyStatic;
public class proxyStatic {
public static void main(String[] args) {
A a = new A();
B b = new B(a);
b.print();
}
/**
* 「原类」
* 实现print
*/
public static class A implements print{
@Override
public void print(){
System.out.println("A你好");
}
}
/**
* 「新类」
* 实现同一个接口print
*/
public static class B implements print{
//构造方法传入「原类」
B(A source){ a=source; }
public static A a;
/**
* 增强
*/
@Override
public void print(){
System.out.println("B之前");
a.print();
System.out.println("B之后");
}
}
public interface print{
public void print();
}
}
静态代理就是需要在每个需要被代理的「原类」都实现一个「新类」,但是一些重复的功能我们可能不希望重复写,例如上面的例子,例如还有一个C类也需要被增强,你就要在构造更多的B来满足要求
二、动态代理
动态代理即将代理类的生层过程抽出来,由代理对象生成器去生成增强的代理类。
动态代理一般有两种方式,一种基于反射实现的「JDK」、另一种基于字节码生成的CGLIB代理。
1.JDK代理
JDK代理类的生成交给Proxy类来实现,JDK代理通过反射实现来一个代理类,所有的方法都通过InvocationHandler的invoker进行拦截
public class JdkProxy {
public static void main(String[] arg) {
A real1 = new A();
ProxyAHandler proxyAHandler = new ProxyAHandler(real1);
/**
* 生成代理类的过程交给Proxy去做
*/
Print proxyA = (Print) Proxy.newProxyInstance(
A.class.getClassLoader(),
new Class[]{Print.class},
proxyAHandler);
proxyA.print();
}
private static class A implements Print {
@Override
public void print() {
System.out.println("A你好");
selfTransfer();
}
@Override
public void selfTransfer(){
System.out.println("A我在内部被调用不会被代理");
}
}
private static class ProxyAHandler implements InvocationHandler {
public ProxyAHandler(Object source) {
this.source = source;
}
private Object source;
/**
* 不管是什么方法,都会被代理,除了类内部自己调用,因为类内部自己调用,没有走到代理类
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + ",invoke前");
Object o = method.invoke(source, args);
System.out.println(method.getName() + ",invoke后");
return o;
}
}
private interface Print {
void print();
//自己调自己
void selfTransfer();
}
}
print,invoke前 A你好 A我在内部被调用不会被代理 print,invoke后
2.CGLIB代理
通过使用Enhancer方法,实现一个继承「原类」的「新类」,对「原类」方法进行拦截增强,代码如下:
public class CglibProxy {
public static void main(String[] arg) {
Enhancer enhancer = new Enhancer();
//设置需要继承哪个类
enhancer.setSuperclass(A.class);
//设置拦截的方法
enhancer.setCallback(new AInterceptorImpl());
//构造代理对象
A a = (A)enhancer.create();
a.print();
}
public static class A{
public void print() {
System.out.println("A你好");
selfTransfer();
}
public void selfTransfer(){
System.out.println("A在内部也会被代理");
}
}
private static class AInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName() + ",invoke前");
Object res = methodProxy.invokeSuper(object, args);
System.out.println(method.getName() + ",invoke后");
return res;
}
}
}
输出
print,invoke前 A你好 selfTransfer,invoke前 A在内部也会被代理 selfTransfer,invoke后 print,invoke后
3.spring 中的CGLIB代理
我们知道spring中的AOP,在类内部调用时是不会触发拦截的,上面的JDK是满足要求的,CGLIB是不满足要求的。那么spring中的CGLIB是如何实现类内部调用不触发的呢?
public class SpringCglibProxy {
public static void main(String[] arg) {
Enhancer enhancer = new Enhancer();
//设置需要继承哪个类
enhancer.setSuperclass(A.class);
//设置拦截的方法
A sourceA = new A();
enhancer.setCallback(new AInterceptorImpl(sourceA));
//构造代理对象
A a = (A)enhancer.create();
a.print();
}
public static class A{
public void print() {
System.out.println("A你好");
selfTransfer();
}
public void selfTransfer(){
System.out.println("A在内部不会被代理");
}
}
private static class AInterceptorImpl implements MethodInterceptor {
//类似JDK,将source类传入使用
private A a;
AInterceptorImpl(A source){
a=source;
}
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(method.getName() + ",invoke前");
//invoke指定类,而不是super类
Object res = methodProxy.invoke(a, args);
System.out.println(method.getName() + ",invoke后");
return res;
}
}
}
输出:
print,invoke前 A你好 A在内部不会被代理 print,invoke后