AOP都是使用设计模式的代理模式来实现的
jdk的是通过动态代理 且目标类必须有接口
为啥要有接口 建议可以看看 这篇 https://blog.csdn.net/zhangerqing/article/details/42504281 笔者下面也有JDK1.7的源码分析,该博客是分析JDK1.8的 出入不大 基本一样
现在先来实现JDK 的动态代理
首先是需要被增强的目标类与目标类的接口
public interface SourceAble {
void method();
}
public class Source implements SourceAble {
@Override
public void method() {
System.out.println("this is source method");
}
}
实现自己的 InvocationHandler 这里实现切面的增强 这里前后都做了增强 在Spring就是@Around 切面
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target; //们既然要做代理,我们必须知道我们是给谁做代理,这里的obj就是被代理者。
MyInvocationHandler() {
super();
}
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target,args);
atfer();
return result;
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
这样就完成切面的操作了 是不是很简单
然后调用jdk反射包的代理类来实现,下面是测试类
public class Test {
public static void main(String[] args) {
System.out.println("-----------动态代理--------------");
//动态代理测试
SourceAble sourceAble1 = new Source();//被代理的对象
InvocationHandler invocationHandler = new MyInvocationHandler(sourceAble1);//
//代理对象
SourceAble dynamicProxy = (SourceAble) java.lang.reflect.Proxy.newProxyInstance(sourceAble1.getClass().getClassLoader(),sourceAble1.getClass().getInterfaces(),invocationHandler);
dynamicProxy.method();
}
}
执行动态代理类的方法
接下来我们也来简单用cglib来实现AOP
首先导入cglib包
目标类User
public class User {
private String name;
public void playName(String name){
System.out.println(" 这是 palyName 方法 参数被偷换啦!参数是:"+name);
}
public void save(){
System.out.println("this is save 方法 :";
}
}
Cglib代理 这里是实现MethodInterceptor来做到切面的增强
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor{
public Object getProxy(Class<?> clazz) {//这里需要知道代理的对象 传入被代理对象的class对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();//返回代理对象
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
// 拦截父类所有方法的调用
System.out.println(method.getName()+":方法执行前......");
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(o,new Object[]{"ssss"});//这里可以拦截所有的父类方法参数
System.out.println(method.getName()+"方法执行结果:"+result);//这里可以拦截所有父类方法的返回值
System.out.println(method.getName()+":方法执行后");
return result;
}
}
然后是测试类
public class Test {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
User user = (User) proxy.getProxy(new User().getClass());
user.playName("kaizen");//明明是kaizen 输出是SSSS 代理模式坑爹啊
user.save("kaizen");
}
}
测试结果 这里注意一下参数会拦截所有的方法!
这里还能修改参数,执行结果,不过使用asm好像会导致性能问题,由于笔者能力有限,也说不出个所以然~
最后对JDK动态代理为什么要实现接口,可以看看笔者写的是否对不对,如果有错麻烦指导一下,本人查看的是JDK1.7
为啥要有接口
首先看 newProxyInstance这个方法里
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)//参数
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
final Class<?>[] intfs = interfaces.clone();//接口浅拷贝
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {//检查是否能访问 这边不研究
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);//这边就是生成代理对象的class
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);//这里获得的是代理对象放置InvocationHandler的构造函数
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);//调用构造函数生成代理类
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
这里还能补充一个知识点:
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
重点应该在
Class<?> cl = getProxyClass0(loader, intfs);//这边就是生成代理对象的class
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache是个缓存
先从缓存里查一下,如果存在,直接返回代理对象的class,不存在就新创建代理对象的class。具体的代码
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory)
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
apply()是Proxy类的内部类ProxyClassFactory实现其接口的一个方法
R apply(T t, U u);