1. 動態代理 Jdk 和Cglib
一、原理區別:
java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
1、如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
package com.lvyuanj.core.service;
public interface UserService{
void login(String username);
void exit(String username);
}
package com.lvyuanj.core.service.Impl;
import com.lvyuanj.core.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public void login(String username) {
System.out.println(username+"進行登錄業務驗證");
}
@Override
public void exit(String username) {
System.out.println("exit---->"+username);
}
}
package com.lvyuanj.core.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start------->");
Object result = method.invoke(target, args);
System.out.println("end---------<");
return result;
}
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
}
}
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
UserService userService0 = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService0);
UserService myProxyUserService = (UserService) myInvocationHandler.getProxy();
myProxyUserService.login("zhangsan");
}
}
2. Spring Aop源碼解析
package com.lvyuanj.core.service;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AuthAspect {
@Around("execution(* com.lvyuanj.core.service.Impl.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start ....");
long l = System.currentTimeMillis();
joinPoint.proceed();
System.out.println("耗時:"+ (System.currentTimeMillis()-l));
}
}
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAopDemo.class);
UserService userService = applicationContext.getBean(UserService.class);
String arvin = "arvin";
userService.login(arvin);
}
}
- 時序圖:
new AnnotationConfigApplicationContext
> org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
>org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
>org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
>org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy --- 判斷使用JdkDynamicAopProxy 和 ObjenesisCglibAopProxy 代理;是否實現了接口
>org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) -- 獲取代理對象
>java.lang.reflect.Proxy#newProxyInstance
>java.lang.reflect.Proxy#getProxyClass0
>java.lang.reflect.Proxy.ProxyClassFactory#apply
---->byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); --- 代理類名稱獲取class字節,
---->defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); -- 通過字節文件生成Class
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAopDemo.class);
UserService userService = applicationContext.getBean(UserService.class);
String arvin = "arvin";
userService.login(arvin);
byte[] userServices = ProxyGenerator.generateProxyClass("UserServiceImpl", new Class[]{UserServiceImpl.class});
FileOutputStream fileOutputStream = new FileOutputStream("D://UserServiceImpl.class");
fileOutputStream.write(userServices);
fileOutputStream.close();
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class UserServiceImpl extends Proxy implements com.lvyuanj.core.service.Impl.UserServiceImpl {
private static Method m1;
private static Method m3;
private static Method m8;
private static Method m2;
private static Method m6;
private static Method m5;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m4;
public UserServiceImpl(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void login(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void notify() throws {
try {
super.h.invoke(this, m8, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void wait(long var1) throws InterruptedException {
try {
super.h.invoke(this, m6, new Object[]{var1});
} catch (RuntimeException | InterruptedException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final void wait(long var1, int var3) throws InterruptedException {
try {
super.h.invoke(this, m5, new Object[]{var1, var3});
} catch (RuntimeException | InterruptedException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final Class getClass() throws {
try {
return (Class)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void notifyAll() throws {
try {
super.h.invoke(this, m9, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void wait() throws InterruptedException {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | InterruptedException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("login", Class.forName("java.lang.String"));
m8 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("notify");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m6 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait", Long.TYPE);
m5 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait", Long.TYPE, Integer.TYPE);
m7 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("getClass");
m9 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("notifyAll");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m4 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
接着把得到的 $Proxy0 實例強制轉換成UserServiceImpl,並將引用賦給subject。當執行userService.login()方法時,就調用了$Proxy0類中的login()方法,進而調用父類Proxy中的h的invoke()方法.即InvocationHandler.invoke()
1.爲什麼我們java動態代理被代理對象必須是接口了?
答: 由於java是單繼承多實現,通過上面反編譯獲取UserServiceImpl 代理類源碼可用出來,UserServiceImpl 默認就已經繼承了Proxy類,所以代理對象必須要有實現的接口;