詳解java中靜態署理完成機制。本站提示廣大學習愛好者:(詳解java中靜態署理完成機制)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解java中靜態署理完成機制正文
署理形式是經常使用的java設計形式,它的特點是署理類與拜托類有異樣的接口,署理類重要擔任為拜托類預處置新聞、過濾新聞、把新聞轉發給拜托類,和過後處置新聞等。署理類與拜托類之間平日會存在聯系關系關系,一個署理類的對象與一個拜托類的對象聯系關系,署理類的對象自己其實不真正完成辦事,而是經由過程挪用拜托類的對象的相干辦法,來供給特定的辦事。
JAVA各類靜態署理完成的比擬
接口
interface AddInterface{
int add(int a, int b);
}
interface SubInterface{
int sub(int a, int b);
}
完成類
class Arithmetic implements AddInterface, SubInterface{
@Override
public int sub(int a, int b) {
return a-b;
}
@Override
public int add(int a, int b) {
return a+b;
}
}
方法1: JDK自帶的靜態署理
1、完成方法
Java在JDK1.3後引入的靜態署理機制,使我們可以在運轉期靜態的創立署理類。應用靜態署理完成AOP須要有四個腳色:被署理的類,被署理類的接口,織入器,和InvocationHandler,而織入器應用接口反射機制生成一個署理類,然後在這個署理類中織入代碼。被署理的類是AOP裡所說的目的,InvocationHandler是切面,它包括了Advice和Pointcut。
2、vInvocationHandler接口的完成
class JdkDPQueryHandler implements InvocationHandler{
private Arithmetic real;
public JdkDPQueryHandler(Arithmetic real){
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println(method);
System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
Object result = method.invoke(real, args);
System.out.println("the method: "+methodName+"停止, 成果: " + result);
return result;
}
}
3、創立署理類而且挪用署理類
public class Main{
private static int a = 4, b = 2;
public static Object createJDKProxy(Arithmetic real){
Object proxyArithmetic = Proxy.newProxyInstance(real.getClass().getClassLoader(),
real.getClass().getInterfaces(), new JdkDPQueryHandler(real));
return proxyArithmetic;
}
public static void main(String[] args){
Arithmetic real = new Arithmetic();
Object proxyArithmetic = createJDKProxy(real);
((AddInterface)proxyArithmetic).add(a, b);
((SubInterface)proxyArithmetic).sub(a, b);
}
}
方法2:靜態字節碼生成(cglib)
1、完成方法
Enhancer和MethodInterceptor。Enhancer可以用來靜態的生成一個類,這個類可以繼續指定的一個類,完成指定的一些接口。同時,Enhancer在生成一個類之前須要指定一個Callback,當類辦法挪用時,辦法的履行被分派給這個Callback,MethodInterceptor是一個應用比擬多的繼續自Callback的接口,它只要一個辦法聲明。
2、接口InvocationHandler(jdk中)和接口MethodInterceptor(cglib中)比較
public interface MethodInterceptor extends Callback {
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
從參數組成上,methodInterceptor的輸出參數比Invocationhandler多1個,其實前3個參數對象的寄義與Invocationhandler的寄義是雷同的。
第一個參數表現挪用辦法來自哪一個對象;
第二個參數表現挪用辦法的Method對象;
第三個參數表現此次挪用的輸出參數列表;
多出來的參數是MethodProxy 類型的,它應當是cglib生成用來取代Method對象的一個對象,應用MethodProxy比挪用JDK本身的Method直接履行辦法效力會有晉升。
3、完成1
MethodInterceptor接口的完成
class CglibDPQueryInterceptor implements MethodInterceptor{
private Arithmetic real;
public CglibDPQueryInterceptor(Arithmetic real){
this.real = real;
}
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
System.out.println(method);
System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
//Object result = method.invoke(real, args);//兩種方法都是可以得
Object result = proxy.invoke(real, args);
System.out.println("the method: "+methodName+"停止, 成果: " + result);
return result;
}
}
創立署理類並挪用署理類
public class Main{
private static int a = 4, b = 2;
public static Object createCglibProxy(Arithmetic real){
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new CglibDPQueryInterceptor(real));
enhancer.setInterfaces(real.getClass().getInterfaces());
return enhancer.create();
}
public static void main(String[] args){
Arithmetic real = new Arithmetic();
Object proxyArithmetic = createCglibProxy(real);
((AddInterface)proxyArithmetic).add(a, b);
((SubInterface)proxyArithmetic).sub(a, b);
}
}
留意了,MethodProxy在對履行函數的時刻,供給了2個辦法
public Object invoke (Object obj, Object[] args) throws Throwable public Object invokeSuper(Object obj, Object[] args) throws Throwable
個中,javadoc上說這個invoke()辦法可以用於雷同類中的其他對象的辦法履行,也就是說這個辦法中的obj須要傳入雷同一個類的另外一個對象(上述辦法中就是傳入了Arithmetic類的分歧對象),不然會進入無窮遞歸輪回(測試以後還真是湧現了StackOverflowError)。細心的想想就會發明,public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)中的target是完成的署理類對象,經由過程target挪用add()辦法時會觸發intercept()辦法被挪用,假如在intercept()辦法中再挪用method.invoke(target, args),就相當於add()辦法中又挪用add()辦法,招致無窮的遞歸輪回。然則假如履行method.invoke(real, args)則不會,由於real和target是統一個類分歧對象,real是真實邏輯主題,target是真實主題real的署理。
上面一個例子來模仿一下:
interface SolveInterface{
void solve();
}
class Real implements SolveInterface{
public void solve(){
System.out.println("Real Solve!");
}
}
class Target extends Real{
private Object obj;
public void setObject(Object obj){
this.obj = obj;
}
private void invoke(){
try {
Method method = SolveInterface.class.getMethod("solve", new Class[]{});
method.invoke(obj, new Class[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
public void solve(){
System.out.println("Target Solve!");
invoke();
}
}
public class Main{public static void main(String[] args) throws Exception{
Target target = new Target();
target.setObject(new Real());//准確
//target.setObject(target);//產生輪回挪用
target.solve();
}
}
其實Method的invoke()辦法會依據obj的類型去挪用對應的solve()辦法,也就是多態性。
4、完成2
MethodInterceptor接口的完成
class CglibDPQueryInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
System.out.println(method);
System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
// 打印類信息 :target.getClass();省略
Object result = proxy.invokeSuper(target, args);
System.out.println("the method: "+methodName+"停止, 成果: " + result);
return result;
}
}
創立署理類並挪用署理類
public class Main{
private static int a = 4, b = 2;
public static Object createCglibProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new CglibDPQueryInterceptor());
enhancer.setSuperclass(Arithmetic.class);
return enhancer.create();
}
public static void main(String[] args){
Arithmetic real = new Arithmetic();
Object proxyArithmetic = createCglibProxy();
((AddInterface)proxyArithmetic).add(a, b);
((SubInterface)proxyArithmetic).sub(a, b);
}
}
留意了,完成2中Enhancer 沒有設置接口,由於設置了Superclass了(也就是署理類的父類是Arithmetic),我們的署理類會繼續它,而Arithmetic曾經完成了我們的接口。為了證實這一點,可以在MethodInterceptor的 intercept辦法中打印 target.getClass()的類信息,你會發明cglib的兩種方法署理類的父類是分歧的。以下:
完成1:
public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends java.lang.Object
完成2:
public class com.test.Arithmetic$$EnhancerByCGLIB$$4fa786eb extends com.test.Arithmetic
方法3:javassist生成靜態署理(署理工場創立 或許 靜態代碼創立)
Javassist是一個編纂字節碼的框架,可讓你很簡略地操作字節碼。它可以在運轉期界說或修正Class。應用Javassist完成AOP的道理是在字節碼加載前直接修正須要切入的辦法。這比應用Cglib完成AOP加倍高效,而且沒太多限制,完成道理以下圖:
完成1:
接口的完成
class JavassistDPQueryHandler implements MethodHandler{
@Override
public Object invoke(Object target, Method method, Method proxy, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println(method);
System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
Object result = proxy.invoke(target, args);
System.out.println("the method: "+methodName+"停止, 成果: " + result);
return result;
}
}
創立署理類並挪用署理類
public class Main{
private static int a = 4, b = 2;
public static Object createJavassistProxy() throws Exception{
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Arithmetic.class);
factory.setHandler(new JavassistDPQueryHandler());
return factory.createClass().newInstance();
}
public static void main(String[] args) throws Exception{
Arithmetic real = new Arithmetic();
Object proxyArithmetic = createJavassistProxy();
((AddInterface)proxyArithmetic).add(a, b);
((SubInterface)proxyArithmetic).sub(a, b);
}
}
留意:MethodHandler接口中invoke辦法的界說,以下:
public Object invoke(Object target, Method method, Method proxy, Object[] args)
method代表挪用辦法的Method對象,proxy是署理類發生並取代method的對象,不然用method.invoke(target, args)會發生無窮輪回挪用。
完成2:
javassist應用靜態java代碼罕見署理進程和前文的辦法略有分歧。javassist外部可以經由過程靜態java代碼,生成字節碼。這類方法創立的靜態署理可以異常靈巧,乃至可以在運轉時發生營業邏輯。
//自界說攔阻器接口
interface InterceptorHandler {
/**
* 挪用靜態署理對象的辦法將反射本辦法,可在本辦法完成中添加相似AOP的事前過後操作,只要在本辦法體中參加以下代碼
* 被署理的辦法才會被履行,前往值將前往給署理最初前往給法式
* @param obj Object 被署理的對象
* @param method Method 被署理對象的辦法
* @param args Object[] 被署理對象的辦法的參數
* @return Object 被署理對象的辦法履行後的前往值
* @throws Throwable
*/
public Object invoke(Object obj, Method method, Object[] args) throws Throwable;
}
//攔阻器的完成
class InterceptorHandlerImpl implements InterceptorHandler{
@Override
public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println(method);
System.out.println("the method: " + methodName + "開端, 參數: "+Arrays.asList(args));
Object result = method.invoke(obj, args);
System.out.println("the method: "+methodName+"停止, 成果: " + result);
return result;
}
}
class MyProxyImpl {
/** 靜態署理類的類名後綴 */
private final static String PROXY_CLASS_NAME_SUFFIX = "$MyProxy_";
/** 攔阻器接口 */
private final static String INTERCEPTOR_HANDLER_INTERFACE = "com.test.InterceptorHandler";
/** 靜態署理類的類名索引,避免類名反復 */
private static int proxyClassIndex = 1;
/**
* 裸露給用戶的靜態署理接口,前往某個接口的靜態署理對象,留意本署理完成需和com.cuishen.myAop.InterceptorHandler攔阻器合營
* 應用,即用戶要應用本靜態署理,需先完成com.cuishen.myAop.InterceptorHandler攔阻器接口
* @param interfaceClassName String 要靜態署理的接口類名, e.g test.StudentInfoService
* @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl
* @param interceptorHandlerImplClassName String 用戶供給的攔阻器接口的完成類的類名
* @return Object 前往某個接口的靜態署理對象
* @throws InstantiationException
* @throws IllegalAccessException
* @throws NotFoundException
* @throws CannotCompileException
* @throws ClassNotFoundException
* @see com.cuishen.myAop.InterceptorHandler
*/
public static Object newProxyInstance(String interfaceClassName, String classToProxy, String interceptorHandlerImplClassName) throws InstantiationException, IllegalAccessException, NotFoundException, CannotCompileException, ClassNotFoundException {
Class interfaceClass = Class.forName(interfaceClassName);
Class interceptorHandlerImplClass = Class.forName(interceptorHandlerImplClassName);
return dynamicImplementsInterface(classToProxy, interfaceClass, interceptorHandlerImplClass);
}
/**
* 靜態完成要署理的接口
* @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl
* @param interfaceClass Class 要靜態署理的接口類, e.g test.StudentInfoService
* @param interceptorHandlerImplClass Class 用戶供給的攔阻器接口的完成類
* @return Object 前往某個接口的靜態署理對象
* @throws NotFoundException
* @throws CannotCompileException
* @throws InstantiationException
* @throws IllegalAccessException
*/
private static Object dynamicImplementsInterface(String classToProxy, Class interfaceClass, Class interceptorHandlerImplClass) throws NotFoundException, CannotCompileException, InstantiationException, IllegalAccessException {
ClassPool cp = ClassPool.getDefault();
String interfaceName = interfaceClass.getName();
//靜態指定署理類的類名
String proxyClassName = interfaceName + PROXY_CLASS_NAME_SUFFIX + proxyClassIndex++;
//要完成的接口的包名+接口名
String interfaceNamePath = interfaceName;
CtClass ctInterface = cp.getCtClass(interfaceNamePath);
CtClass cc = cp.makeClass(proxyClassName);
cc.addInterface(ctInterface);
Method [] methods = interfaceClass.getMethods();
for(int i = 0; i < methods.length; i++) {
Method method = methods[i];
dynamicImplementsMethodsFromInterface(classToProxy, cc, method, interceptorHandlerImplClass, i);
}
return (Object)cc.toClass().newInstance();
}
/**
* 靜態完成接口裡的辦法
* @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl
* @param implementer CtClass 靜態署理類的包裝
* @param methodToImpl Method 靜態署理類外面要完成的接口辦法的包裝
* @param interceptorClass Class 用戶供給的攔阻器完成類
* @param methodIndex int 要完成的辦法的索引
* @throws CannotCompileException
*/
private static void dynamicImplementsMethodsFromInterface(String classToProxy, CtClass implementer, Method methodToImpl, Class interceptorClass, int methodIndex) throws CannotCompileException {
String methodCode = generateMethodCode(classToProxy, methodToImpl, interceptorClass, methodIndex);
CtMethod cm = CtNewMethod.make(methodCode, implementer);
implementer.addMethod(cm);
}
/**
* 靜態組裝辦法體,固然署理外面的辦法完成其實不是簡略的辦法拷貝,而是反射挪用了攔阻器裡的invoke辦法,並將吸收到的參數停止傳遞
* @param classToProxy String 要靜態署理的接口的完成類的類名, e.g test.StudentInfoServiceImpl
* @param methodToImpl Method 靜態署理類外面要完成的接口辦法的包裝
* @param interceptorClass Class 用戶供給的攔阻器完成類
* @param methodIndex int 要完成的辦法的索引
* @return String 靜態組裝的辦法的字符串
*/
private static String generateMethodCode(String classToProxy, Method methodToImpl, Class interceptorClass, int methodIndex) {
String methodName = methodToImpl.getName();
String methodReturnType = methodToImpl.getReturnType().getName();
Class[] parameters = methodToImpl.getParameterTypes();
Class[] exceptionTypes = methodToImpl.getExceptionTypes();
StringBuffer exceptionBuffer = new StringBuffer();
//組裝辦法的Exception聲明
if(exceptionTypes.length > 0) exceptionBuffer.append(" throws ");
for(int i = 0; i < exceptionTypes.length; i++) {
if(i != exceptionTypes.length - 1) exceptionBuffer.append(exceptionTypes[i].getName()).append(",");
else exceptionBuffer.append(exceptionTypes[i].getName());
}
StringBuffer parameterBuffer = new StringBuffer();
//組裝辦法的參數列表
for(int i = 0; i < parameters.length; i++) {
Class parameter = parameters[i];
String parameterType = parameter.getName();
//靜態指定辦法參數的變量名
String refName = "a" + i;
if(i != parameters.length - 1) parameterBuffer.append(parameterType).append(" " + refName).append(",");
else parameterBuffer.append(parameterType).append(" " + refName);
}
StringBuffer methodDeclare = new StringBuffer();
//辦法聲明,因為是完成接口的辦法,所所以public
methodDeclare.append("public ").append(methodReturnType).append(" ").append(methodName).append("(").append(parameterBuffer).append(")").append(exceptionBuffer).append(" {\n");
String interceptorImplName = interceptorClass.getName();
//辦法體
methodDeclare.append(INTERCEPTOR_HANDLER_INTERFACE).append(" interceptor = new ").append(interceptorImplName).append("();\n");
//反射挪用用戶的攔阻器接口
methodDeclare.append("Object returnObj = interceptor.invoke(Class.forName(\"" + classToProxy + "\").newInstance(), Class.forName(\"" + classToProxy + "\").getMethods()[" + methodIndex + "], ");
//傳遞辦法裡的參數
if(parameters.length > 0) methodDeclare.append("new Object[]{");
for(int i = 0; i < parameters.length; i++) {
//($w) converts from a primitive type to the corresponding wrapper type: e.g.
//Integer i = ($w)5;
if(i != parameters.length - 1) methodDeclare.append("($w)a" + i + ",");
else methodDeclare.append("($w)a" + i);
}
if(parameters.length > 0) methodDeclare.append("});\n");
else methodDeclare.append("null);\n");
//對換用攔阻器的前往值停止包裝
if(methodToImpl.getReturnType().isPrimitive()) {
if(methodToImpl.getReturnType().equals(Boolean.TYPE)) methodDeclare.append("return ((Boolean)returnObj).booleanValue();\n");
else if(methodToImpl.getReturnType().equals(Integer.TYPE)) methodDeclare.append("return ((Integer)returnObj).intValue();\n");
else if(methodToImpl.getReturnType().equals(Long.TYPE)) methodDeclare.append("return ((Long)returnObj).longValue();\n");
else if(methodToImpl.getReturnType().equals(Float.TYPE)) methodDeclare.append("return ((Float)returnObj).floatValue();\n");
else if(methodToImpl.getReturnType().equals(Double.TYPE)) methodDeclare.append("return ((Double)returnObj).doubleValue();\n");
else if(methodToImpl.getReturnType().equals(Character.TYPE)) methodDeclare.append("return ((Character)returnObj).charValue();\n");
else if(methodToImpl.getReturnType().equals(Byte.TYPE)) methodDeclare.append("return ((Byte)returnObj).byteValue();\n");
else if(methodToImpl.getReturnType().equals(Short.TYPE)) methodDeclare.append("return ((Short)returnObj).shortValue();\n");
} else {
methodDeclare.append("return (" + methodReturnType + ")returnObj;\n");
}
methodDeclare.append("}");
System.out.println(methodDeclare.toString());
return methodDeclare.toString();
}
}
public class Main{
public static void main(String[] args) throws Exception{
//分離對應 署理類要完成的接口類名, 須要署理類的類名, 用戶自界說攔阻器完成類的類名
Object proxyArithmetic = MyProxyImpl.newProxyInstance("com.test.ArithmeticInterface", "com.test.Arithmetic",
"com.test.InterceptorHandlerImpl");
((ArithmeticInterface)proxyArithmetic).add(a, b);
((ArithmeticInterface)proxyArithmetic).sub(a, b);
}
}
打印一下靜態完成接口的代碼以下:
public int add(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[0], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}
public int sub(int a0,int a1) {
com.test.InterceptorHandler interceptor = new com.test.InterceptorHandlerImpl();
Object returnObj = interceptor.invoke(Class.forName("com.test.Arithmetic").newInstance(), Class.forName("com.test.Arithmetic").getMethods()[1], new Object[]{($w)a0,($w)a1});
return ((Integer)returnObj).intValue();
}
以上就是關於java中靜態署理完成機制的具體引見,願望對年夜家的進修有所贊助。