`

基于ASM轻量型AOP框架实现

阅读更多
Spring AOP 的底层实现是Java Proxy和CGLib,而CGLib的底层实现是ASM.
本示例直接从ASM实现轻量型AOP框架


1.XSD配置文件约束:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.youisoft.org/aaop" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.youisoft.org/aaop" elementFormDefault="qualified" version="1.0">
	<xs:simpleType name="match">
		<xs:restriction base="xs:string">
			<xs:enumeration value="dynamic"/>
			<xs:enumeration value="exception"/>
			<xs:enumeration value="none"/>
			<xs:enumeration value="parameter"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:complexType name="Descriptor">
		<xs:choice>
			<xs:element name="args" type="Args" minOccurs="0" maxOccurs="1"/>
			<xs:element name="pattern" type="xs:string" minOccurs="0" maxOccurs="1"/>
		</xs:choice>
	</xs:complexType>
	<xs:complexType name="Args">
		<xs:sequence>
			<xs:element name="arg" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
			<xs:element name="ret" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
			<xs:element name="exp" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>
	<xs:complexType name="Config">
		<xs:sequence>
			<xs:element name="service" type="Service" minOccurs="0" maxOccurs="unbounded"/>
		</xs:sequence>
	</xs:complexType>
	<xs:element name="config" type="Config"/>
	<xs:complexType name="Adapter">
		<xs:sequence/>
		<xs:attribute name="class" use="optional" type="xs:string"/>
		<xs:attribute name="name" use="optional" type="xs:string"/>
	</xs:complexType>
	<xs:complexType name="Service">
		<xs:sequence minOccurs="0">
			<xs:element name="adapter" type="Adapter" minOccurs="0" maxOccurs="1"/>
			<xs:element name="component" type="Component" minOccurs="1" maxOccurs="1"/>
			<xs:element name="method" type="Method" minOccurs="1" maxOccurs="1"/>
		</xs:sequence>
		<xs:attribute name="class" use="optional" type="xs:string"/>
		<xs:attribute name="match" use="optional" default="none" type="match"/>
		<xs:attribute name="name" use="optional" type="xs:string"/>
		<xs:attribute name="static" use="optional" default="false" type="xs:boolean"/>
		<xs:attribute name="style" use="optional" default="return" type="Style"/>
	</xs:complexType>
	<xs:complexType name="Component">
		<xs:sequence>
			<xs:element name="method" type="Method" minOccurs="0" maxOccurs="1"/>
		</xs:sequence>
		<xs:attribute name="class" use="optional" type="xs:string"/>
		<xs:attribute name="name" use="optional" type="xs:string"/>
	</xs:complexType>
	<xs:simpleType name="Style">
		<xs:restriction base="xs:string">
			<xs:enumeration value="after"/>
			<xs:enumeration value="before"/>
			<xs:enumeration value="return"/>
			<xs:enumeration value="throw"/>
		</xs:restriction>
	</xs:simpleType>
	<xs:complexType name="Method">
		<xs:sequence>
			<xs:element name="descriptor" type="Descriptor" minOccurs="0" maxOccurs="1"/>
		</xs:sequence>
		<xs:attribute name="match" use="optional" default="none" type="match"/>
		<xs:attribute name="name" use="optional" type="xs:string"/>
	</xs:complexType>
</xs:schema>

XML实现例子

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.youisoft.org/aaop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.youisoft.org/aaop xsd/aaop-1.0.xsd ">
  
  <service class="org.youisoft.sample.SampleService"
  	name="sampleService" style="return">
  	<component class="org.youisoft.sample.SampleComponent"
  		name="sampleComponent">
  		<method name="invoke"></method>
  	</component>
  	<method name="sample">
  		<descriptor>
  				<args>
  					<arg>org.youisoft.sample.Request</arg>
  					<ret>org.youisoft.sample.Response</ret></args></descriptor>
  	</method>
  </service>


</config>


2.配置文件容器及常量:

package org.youisoft.config;

/**
 * 
 * @author janly
 *
 */
public class Configs{
	private java.util.List list=new java.util.ArrayList();
	
	/**
	 * 
	 * @param config
	 */
	public void setConfig(Config config){
		list.add(config);
	}

	/**
	 * @return the configs
	 */
	public Config[] getConfigs() {
		return (Config[])list.toArray(new Config[]{});
	}
	
	
}


package org.youisoft;
/**
 * 
 * @author janly
 *
 */
public interface AopStyle{
	
	public final static String STYLE_BEFORE="before";
	public final static String STYLE_AFTER="after";
	public final static String STYLE_THROW="throw";
	public final static String STYLE_RETURN="return";
	public final static String MATCH_NONE="none";
	public final static String MATCH_DYNAMIC="dynamic";
	public final static String MATCH_PARAMETER="parameter";
	public final static String MATCH_EXCEPTION="exception";
	/**
	 * 
	 * @param style
	 */
	public void setStyle(String style);
	
	
	
	

}




3.配置文件解析:

package org.youisoft.config;

import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
 * 
 * @author janly
 *
 */
public class XmlConfig {
	private final static String SERVICE="/config/service";
	private final static String METHODADAPTER="/config/service/adapter";
	private final static String SERVICEMETHOD="/config/service/method";
	private final static String SERVICEPATTERN="/config/service/method/descriptor/pattern";
	private final static String SERVICEARG="/config/service/method/descriptor/args/arg";
	private final static String SERVICERET="/config/service/method/descriptor/args/ret";
	private final static String SERVICEEXP="/config/service/method/descriptor/args/exp";
	private final static String COMPONENT="/config/service/component";
	private final static String COMPONENTMETHOD="/config/service/component/method";
	private final static String COMPONENTPATTERN="/config/service/component/method/descriptor/pattern";
	private final static String COMPONENTARG="/config/service/component/method/descriptor/args/arg";
	private final static String COMPONENTRET="/config/service/component/method/descriptor/args/ret";
	private final static String COMPONENTEXP="/config/service/component/method/descriptor/args/exp";
	
	
	public static Configs parserXml(org.xml.sax.InputSource inputSource){
		final Configs configs=new Configs();
		
		SAXParserFactory saxFactory=SAXParserFactory.newInstance();
		saxFactory.setNamespaceAware(true);
		try {
			javax.xml.parsers.SAXParser saxParser=saxFactory.newSAXParser();
			
			saxParser.parse(inputSource, new DefaultHandler(){
				private PathStack ps=new PathStack();
				private Config config;
				/* (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
				 */
				public void characters(char[] ch, int start, int length)
						throws SAXException {
					
					if(SERVICEPATTERN.equals(ps.getPath())){
						config.getServiceMethod().setPattern(new String(ch,start,length));
					}
					
					if(COMPONENTPATTERN.equals(ps.getPath())){
						config.getComponentMethod().setPattern(new String(ch,start,length));
					}
					
					if(SERVICEARG.equals(ps.getPath())){
						config.getServiceMethod().addArg(new String(ch,start,length));
					}
					
					if(SERVICERET.equals(ps.getPath())){
						config.getServiceMethod().addRet(new String(ch,start,length));
					}
					
					if(SERVICEEXP.equals(ps.getPath())){
						config.getServiceMethod().addExp(new String(ch,start,length));
					}
					
					if(COMPONENTARG.equals(ps.getPath())){
						config.getComponentMethod().addArg(new String(ch,start,length));
					}
					
					if(COMPONENTRET.equals(ps.getPath())){
						config.getComponentMethod().addRet(new String(ch,start,length));
					}
					
					if(COMPONENTEXP.equals(ps.getPath())){
						config.getComponentMethod().addExp(new String(ch,start,length));
					}
					
					
					
					
					
					
				}

				/* (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
				 */
				public void endElement(String uri, String localName, String name)
						throws SAXException {
					if(SERVICE.equals(ps.getPath())){
						configs.setConfig(config);
					}
					ps.pop();
					
				}

				/* (non-Javadoc)
				 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
				 */
				public void startElement(String uri, String localName,
						String name, Attributes attributes) throws SAXException {
					ps.push(localName);
					
					if(SERVICE.equals(ps.getPath())){
						config=new Config();
						config.setServiceClassName(attributes.getValue("class"));
						config.setServiceName(attributes.getValue("name"));
						if(attributes.getValue("style")!=null) config.setStyle(attributes.getValue("style"));
						if(attributes.getValue("match")!=null) config.setMatch(attributes.getValue("match"));
						if(attributes.getValue("static")!=null) config.setStaticInvoke(new Boolean(attributes.getValue("static")).booleanValue());
					}
					
					if(METHODADAPTER.equals(ps.getPath())){
						config.setAdapterClassName(attributes.getValue("class"));
						config.setAdapterName(attributes.getValue("name"));
						
					}
					
					if(SERVICEMETHOD.equals(ps.getPath())){
						config.getServiceMethod().setMethodName(attributes.getValue("name"));
						config.getServiceMethod().setMatch(attributes.getValue("match"));
						
					}
					
					if(COMPONENT.equals(ps.getPath())){
						config.setComponentClassName(attributes.getValue("class"));
						config.setComponentName(attributes.getValue("name"));
					}
					
					if(COMPONENTMETHOD.equals(ps.getPath())){
						config.getComponentMethod().setMethodName(attributes.getValue("name"));
						config.getComponentMethod().setMatch(attributes.getValue("match"));
					}
					
					
				}
				
					/**
					 * 
					 * @author janly
					 *
					 */
					class PathStack extends java.util.Stack{
						/**
						 * 
						 */
						private static final long serialVersionUID = 1L;
						private java.util.Stack stack=new java.util.Stack();
						
						public String getPath(){
							java.lang.StringBuffer sb=new java.lang.StringBuffer();
							for(int i=0;i<stack.size();i++){
								sb.append("/");
								sb.append(stack.get(i).toString());
							}
							
							return sb.toString();
							
						}

						/* (non-Javadoc)
						 * @see java.util.Stack#empty()
						 */
						public boolean empty() {
							// TODO Auto-generated method stub
							return stack.empty();
						}

						/* (non-Javadoc)
						 * @see java.util.Stack#peek()
						 */
						public synchronized Object peek() {
							// TODO Auto-generated method stub
							return stack.peek();
						}

						/* (non-Javadoc)
						 * @see java.util.Stack#pop()
						 */
						public synchronized Object pop() {
							// TODO Auto-generated method stub
							return stack.pop();
						}

						/* (non-Javadoc)
						 * @see java.util.Stack#push(java.lang.Object)
						 */
						public Object push(Object arg0) {
							// TODO Auto-generated method stub
							return stack.push(arg0);
						}

						/* (non-Javadoc)
						 * @see java.util.Stack#search(java.lang.Object)
						 */
						public synchronized int search(Object o) {
							// TODO Auto-generated method stub
							return stack.search(o);
						}
						
						
					}
			
				}
			
			
			);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return configs;
	}
	


}


4.AOP实现,包括方法前拦截,方法返回拦截,异常拦截等:

package org.youisoft.config;

import java.io.IOException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.youisoft.AopStyle;
/**
 * 
 * @author janly
 *
 */
public class Config {
	private String serviceName;
	private String serviceClassName;
	private String componentClassName;
	private String componentName;
	private String adapterClassName;
	private String adapterName;
	private boolean staticInvoke;
	private String style=AopStyle.STYLE_RETURN;
	private String match=AopStyle.MATCH_NONE;
	private final Method serviceMethod=new Method();
	private final Method componentMethod=new Method();
	private boolean catchValue=false;
	
	/**
	 * initialise the default method name,method arguments,method return,method exception of component.
	 */
	public void initServiceComponent(){
		
		//default method name
		if(this.getComponentMethod().getMethodName()==null) 
			this.getComponentMethod().setMethodName(this.getServiceMethod().getMethodName());
		
		
		if(this.componentMethod.getDescriptor()==null){
			for(java.util.Iterator it=this.getServiceMethod().getArgs().iterator();it.hasNext();){
				this.getComponentMethod().addArg(it.next().toString());
			}
			
			for(java.util.Iterator it=this.getServiceMethod().getRets().iterator();it.hasNext();){
				this.getComponentMethod().addRet(it.next().toString());
			}
		}
		
		
		if(this.componentMethod.getExceptions().length==0){
			for(java.util.Iterator it=this.getServiceMethod().getExps().iterator();it.hasNext();){
				this.getComponentMethod().addExp(it.next().toString());
			}
			
		}

	}
	
	
	/**
	 * 
	 * @param data
	 * @return
	 */
	public byte[] config(byte[] data){
		org.objectweb.asm.ClassReader cr = new org.objectweb.asm.ClassReader(data);
		return config(cr);
	}
	
	/**
	 * 
	 * @return
	 */
	public byte[] config(){
		java.io.InputStream is=this.getClass().getClassLoader().getResourceAsStream(Config.this.getServiceClassName().concat(".class"));
		org.objectweb.asm.ClassReader cr=null;
		try {
			cr = new org.objectweb.asm.ClassReader(is);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return config(cr);
	}
	

	/**
	 * the main method of AOP.
	 * first: method of service in configuration match the destination method.
	 * second: method of component in configuration match the service method.
	 * @return
	 */
	private byte[] config(org.objectweb.asm.ClassReader cr){
		try{
			org.objectweb.asm.ClassWriter cw=new org.objectweb.asm.ClassWriter(cr,ClassWriter.COMPUTE_MAXS);
			org.objectweb.asm.ClassAdapter ca=new org.objectweb.asm.ClassAdapter(cw){
				public MethodVisitor visitMethod(int arg0, String arg1, String arg2,String arg3, String[] arg4) {
					MethodVisitor mv=super.visitMethod(arg0, arg1, arg2, arg3, arg4);
					if(mv!=null){
						boolean match=false;
						if(arg1.equals(serviceMethod.getMethodName())){
							if(serviceMethod.getMatch().equals(AopStyle.MATCH_NONE)||
									serviceMethod.getMatch().equals(AopStyle.MATCH_DYNAMIC)
									){
								serviceMethod.setPattern(arg2);
								serviceMethod.clearExps();
								for(int i=0;arg4!=null&&i<arg4.length;i++){
									serviceMethod.addExp(arg4[i]);
								}
								match=true;
							}else if(serviceMethod.getMatch().equals(AopStyle.MATCH_PARAMETER)&&
									serviceMethod.getDescriptor().equals(arg2)){
								serviceMethod.clearExps();
								for(int i=0;arg4!=null&&i<arg4.length;i++){
									serviceMethod.addExp(arg4[i]);
								}
								match=true;
							}else if(serviceMethod.getMatch().equals(AopStyle.MATCH_EXCEPTION)&&
									serviceMethod.getDescriptor().equals(arg2)){
							
								if(arg4!=null&&serviceMethod.getExceptions().length==arg4.length){
									match=true;
									for(int i=0;i<arg4.length;i++){
										if(!arg4[i].equals(serviceMethod.getExceptions()[i])) match=false;
										
									}
								}	
							}
						}
				

						if(match){
							if(Config.this.getAdapterClassName()!=null){
								try {
									Class clazz=Class.forName(Config.this.getAdapterClassName());
									if(MethodAdapter.class.isAssignableFrom(clazz)){
										java.lang.reflect.Constructor con=clazz.getConstructor(new Class[]{MethodVisitor.class});
										mv=(MethodAdapter)con.newInstance(new Object[]{mv});
										if(AopStyle.class.isAssignableFrom(clazz)){
											((AopStyle)mv).setStyle(Config.this.getStyle());
										}
									}
								} catch (Exception e) {
									e.printStackTrace();
								}
							}else{
								
								if(Config.this.getStyle().equals(AopStyle.STYLE_BEFORE)){
									
									mv=new org.objectweb.asm.MethodAdapter(mv){
										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitCode()
										 */
										public void visitCode() {
											if(getServiceComponentMatch()){
												Type[] argType=Type.getArgumentTypes(Config.this.getServiceMethod().getDescriptor());
												if(Config.this.isStaticInvoke()){
													for(int i=1;i<=argType.length;i++){
														super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
													}
													super.visitMethodInsn(Opcodes.INVOKESTATIC,Config.this.getComponentClassName(),
															Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
												}else{
													super.visitTypeInsn(Opcodes.NEW, Config.this.getComponentClassName());
													super.visitInsn(Opcodes.DUP);
													super.visitMethodInsn(Opcodes.INVOKESPECIAL,Config.this.getComponentClassName(), "<init>", "()V");
													
													for(int i=1;i<=argType.length;i++){
														super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
													}
													super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,Config.this.getComponentClassName(),
															Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
												}
												
												super.visitInsn(Opcodes.POP);

											}
											super.visitCode();
										}
										
									};
								}
								
								if(Config.this.getStyle().equals(AopStyle.STYLE_AFTER)){
									mv=new org.objectweb.asm.MethodAdapter(mv){


										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitInsn(int)
										 */
										public void visitInsn(int opcode) {
											if(opcode>=Opcodes.IRETURN&&opcode<=Opcodes.RETURN){
												if(getServiceComponentMatch()){
													Type[] argType=Type.getArgumentTypes(Config.this.getServiceMethod().getDescriptor());
													if(Config.this.isStaticInvoke()){
														for(int i=1;i<=argType.length;i++){
															super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
														}
														super.visitMethodInsn(Opcodes.INVOKESTATIC,Config.this.getComponentClassName(),
																Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
													}else{
														super.visitTypeInsn(Opcodes.NEW, Config.this.getComponentClassName());
														super.visitInsn(Opcodes.DUP);
														super.visitMethodInsn(Opcodes.INVOKESPECIAL,Config.this.getComponentClassName(), "<init>", "()V");
														for(int i=1;i<=argType.length;i++){
															super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
														}
														super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,Config.this.getComponentClassName(),
																Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
														
													}
													super.visitInsn(Opcodes.POP);
											
												}
											}
											super.visitInsn(opcode);
										}
									
									};
								}
								
								if(Config.this.getStyle().equals(AopStyle.STYLE_THROW)){
									mv=new org.objectweb.asm.MethodAdapter(mv){
										private int idx=0;
										private java.util.List lList=new java.util.ArrayList();
										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitLabel(org.objectweb.asm.Label)
										 */
										public void visitLabel(Label arg0) {
											super.visitLabel(arg0);
											if(lList.contains(arg0)&&getServiceComponentMatch()){
												Type[] argType=Type.getArgumentTypes(Config.this.getServiceMethod().getDescriptor());
												super.visitVarInsn(Opcodes.ASTORE,idx+1);
												if(Config.this.isStaticInvoke()){
													for(int i=1;i<=argType.length;i++){
														super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
													}
													if(catchValue) super.visitVarInsn(Opcodes.ALOAD,idx+1);
													super.visitMethodInsn(Opcodes.INVOKESTATIC,Config.this.getComponentClassName(),
															Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
												}else{
													super.visitTypeInsn(Opcodes.NEW, Config.this.getComponentClassName());
													super.visitInsn(Opcodes.DUP);
													super.visitMethodInsn(Opcodes.INVOKESPECIAL,Config.this.getComponentClassName(), "<init>", "()V");

													for(int i=1;i<=argType.length;i++){
														super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
													}
													if(catchValue) super.visitVarInsn(Opcodes.ALOAD,idx+1);
													super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,Config.this.getComponentClassName(),
															Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
												}
												super.visitInsn(Opcodes.POP);
												super.visitVarInsn(Opcodes.ALOAD,idx+1);
											}
											
										}




										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitTryCatchBlock(org.objectweb.asm.Label, org.objectweb.asm.Label, org.objectweb.asm.Label, java.lang.String)
										 */
										public void visitTryCatchBlock(Label arg0, Label arg1,Label arg2, String arg3) {
											if(arg2!=null) this.lList.add(arg2);
											super.visitTryCatchBlock(arg0, arg1, arg2, arg3);
										}




										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
										 */
										public void visitVarInsn(int arg0,
												int arg1) {
											if(arg0>=54&&arg0<=86){
												if(arg1>idx) idx=arg1;
											}
											super.visitVarInsn(arg0, arg1);
										}
									};
								}
								
								
								if(Config.this.getStyle().equals(AopStyle.STYLE_RETURN)){
									mv=new org.objectweb.asm.MethodAdapter(mv){
										
										private int idx=0;
										/* (non-Javadoc)
										 * @see org.objectweb.asm.MethodAdapter#visitVarInsn(int, int)
										 */
										public void visitVarInsn(int arg0,
												int arg1) {
											if(arg0>=54&&arg0<=86){
												if(arg1>idx) idx=arg1;
											}
											super.visitVarInsn(arg0, arg1);
										}
										

										public void visitInsn(int opcode) {
											if(opcode>=Opcodes.IRETURN&&opcode<=Opcodes.RETURN){
												if(getServiceComponentMatch()){
													Type[] argType=Type.getArgumentTypes(Config.this.getServiceMethod().getDescriptor());
													Type retType=Type.getReturnType(Config.this.getServiceMethod().getDescriptor());
													if(catchValue) {
														super.visitVarInsn(retType.getOpcode(Opcodes.ISTORE),idx+1);
													}else{
														super.visitInsn(Opcodes.POP);
													}
													
													if(Config.this.isStaticInvoke()){
														for(int i=1;i<=argType.length;i++){
															super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
														}
														if(catchValue) super.visitVarInsn(retType.getOpcode(Opcodes.ILOAD), idx+1);
														super.visitMethodInsn(Opcodes.INVOKESTATIC,Config.this.getComponentClassName(),
																Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
													}else{
														super.visitTypeInsn(Opcodes.NEW, Config.this.getComponentClassName());
														super.visitInsn(Opcodes.DUP);
														super.visitMethodInsn(Opcodes.INVOKESPECIAL,Config.this.getComponentClassName(), "<init>", "()V");
														for(int i=1;i<=argType.length;i++){
															super.visitVarInsn(argType[i-1].getOpcode(Opcodes.ILOAD), i);
														}
														if(catchValue) super.visitVarInsn(retType.getOpcode(Opcodes.ILOAD), idx+1);
														super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,Config.this.getComponentClassName(),
																Config.this.getComponentMethod().getMethodName(),Config.this.getComponentMethod().getDescriptor());
														
													}

												}
											}
											super.visitInsn(opcode);
										}
									};
								}
							}
			
						}
						
					}
					return mv;
				}
			};
			cr.accept(ca, org.objectweb.asm.ClassReader.SKIP_DEBUG);
			return cw.toByteArray();
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	
	
	
	private boolean getServiceComponentMatch(){
		this.initServiceComponent();
		boolean match=false;
		if(this.getComponentMethod().getMatch().equals(AopStyle.MATCH_NONE)||
				this.getComponentMethod().getMatch().equals(AopStyle.MATCH_PARAMETER)){
			if(this.getComponentMethod().getDescriptor().equals(this.getServiceMethod().getDescriptor())){
				match=true;
			}
			return match;
		}
		
		if(this.getComponentMethod().getMatch().equals(AopStyle.MATCH_DYNAMIC)){
			Type[] sargType=Type.getArgumentTypes(Config.this.getServiceMethod().getDescriptor());
			Type sretType=Type.getReturnType(Config.this.getServiceMethod().getDescriptor());
			Type[] cArgType=Type.getArgumentTypes(Config.this.getComponentMethod().getDescriptor());
			if(sargType.length==cArgType.length-1){
				if(sretType.toString().equals(cArgType[cArgType.length-1].toString())||
						Type.getDescriptor(java.lang.Throwable.class).equals(cArgType[cArgType.length-1].toString())
						){
					match=true;
					catchValue=true;
				}
	
			}
			return match;
		}
		
		
		if(this.getComponentMethod().getMatch().equals(AopStyle.MATCH_EXCEPTION)){
			if(this.getComponentMethod().getDescriptor().equals(this.getServiceMethod().getDescriptor())){
				if(this.getComponentMethod().getExceptions().length==this.getServiceMethod().getExceptions().length){
					match=true;
					for(int i=0;i<this.getComponentMethod().getExceptions().length;i++){
						if(!this.getComponentMethod().getExceptions()[i].equals(this.getServiceMethod().getExceptions()[i])) match=false;
					}
					
				}
			}

			return match;
		}
		
		
		return match;
	}
	
	/**
	 * 
	 * @param str
	 * @param begin
	 * @param end
	 * @return
	 */
	private static String substringBetween(String str,String begin,String end){
		int a=str.indexOf(begin);
		int b=str.lastIndexOf(end);
		return str.substring(a, b);
		
	}
	
	/**
	 * 
	 * @param str
	 * @param begin
	 * @return
	 */
	private static String substringBefore(String str,String begin){
		int a=str.indexOf(begin);
		return str.substring(0,a);
		
	}
	
	/**
	 * 
	 * @param str
	 * @param end
	 * @return
	 */
	private static String substringAfter(String str,String end){
		int a=str.indexOf(end);
		return str.substring(a+1);
		
	}
	
	/**
	 * 
	 * @param s
	 * @param sb
	 */
	public static void converToSimplePattern(String s,java.lang.StringBuffer sb){
		if(s.startsWith("(")) {
			converToSimplePattern(substringBetween(s, "(", ")"),sb);
			return;
		}
		
		if(s.startsWith("[")) {
			converToSimplePattern(substringAfter(s,"["),sb);
			return;
		}
		
		if(s.startsWith("L")){
			sb.append("L");
			converToSimplePattern(substringAfter(s,";"),sb);
			return;
		}
		
		if(s!=null&&s.length()>0){
			sb.append(s.substring(0,1));
			converToSimplePattern(s.substring(1),sb);
			return;
		}
	}
	
	/**
	 * 
	 * @param s
	 * @return
	 */
	public static String converToPattern(String s){
		java.lang.StringBuffer sb=new java.lang.StringBuffer("");
		if(s.equals("void")) sb.append(Type.getDescriptor(void.class));
		if(s.equals("boolean")) sb.append(Type.getDescriptor(boolean.class));
		if(s.equals("int")) sb.append(Type.getDescriptor(int.class));
		if(s.equals("char")) sb.append(Type.getDescriptor(char.class));
		if(s.equals("byte")) sb.append(Type.getDescriptor(byte.class));
		if(s.equals("short")) sb.append(Type.getDescriptor(short.class));
		if(s.equals("float")) sb.append(Type.getDescriptor(float.class));
		if(s.equals("long")) sb.append(Type.getDescriptor(long.class));
		if(s.equals("double")) sb.append(Type.getDescriptor(double.class));
		if(s.equals("boolean[]")) sb.append(Type.getDescriptor(boolean[].class));
		if(s.equals("int[]")) sb.append(Type.getDescriptor(int[].class));
		if(s.equals("char[]")) sb.append(Type.getDescriptor(char[].class));
		if(s.equals("byte[]")) sb.append(Type.getDescriptor(byte[].class));
		if(s.equals("short[]")) sb.append(Type.getDescriptor(short[].class));
		if(s.equals("float[]")) sb.append(Type.getDescriptor(float[].class));
		if(s.equals("long[]")) sb.append(Type.getDescriptor(long[].class));
		if(s.equals("double[]")) sb.append(Type.getDescriptor(double[].class));
		if(s.equals("boolean[][]")) sb.append(Type.getDescriptor(boolean[][].class));
		if(s.equals("int[][]")) sb.append(Type.getDescriptor(int[][].class));
		if(s.equals("char[][]")) sb.append(Type.getDescriptor(char[][].class));
		if(s.equals("byte[][]")) sb.append(Type.getDescriptor(byte[][].class));
		if(s.equals("short[][]")) sb.append(Type.getDescriptor(short[][].class));
		if(s.equals("float[][]")) sb.append(Type.getDescriptor(float[][].class));
		if(s.equals("long[][]")) sb.append(Type.getDescriptor(long[][].class));
		if(s.equals("double[][]")) sb.append(Type.getDescriptor(double[][].class));
		
		if(!sb.toString().equals("")) return sb.toString();

		if(s.endsWith("[][]")) {
			sb.append("[[L"+sb.append(substringBefore(s, "[][]")));
		}else if(s.endsWith("[]")) {
			sb.append("[L"+sb.append(substringBefore(s, "[]")));
		}else{
			sb.append("L"+s);
		}
		sb.append(";");

		return sb.toString();
	}
	
	
	
	
	/**
	 * @return the serviceName
	 */
	public String getServiceName() {
		return serviceName;
	}

	/**
	 * @param serviceName the serviceName to set
	 */
	public void setServiceName(String serviceName) {
		this.serviceName = serviceName;
	}

	/**
	 * @return the serviceClassName
	 */
	public String getServiceClassName() {
		return serviceClassName;
	}

	/**
	 * @param serviceClassName the serviceClassName to set
	 */
	public void setServiceClassName(String serviceClassName) {
		if(serviceClassName!=null) serviceClassName=serviceClassName.replace('.', '/');
 		this.serviceClassName = serviceClassName;
	}

	/**
	 * @return the componentClassName
	 */
	public String getComponentClassName() {
		return componentClassName;
	}

	/**
	 * @param componentClassName the componentClassName to set
	 */
	public void setComponentClassName(String componentClassName) {
		if(componentClassName!=null) componentClassName=componentClassName.replace('.', '/');
		this.componentClassName = componentClassName;
	}

	/**
	 * @return the componentName
	 */
	public String getComponentName() {
		return componentName;
	}

	/**
	 * @param componentName the componentName to set
	 */
	public void setComponentName(String componentName) {
		this.componentName = componentName;
	}

	/**
	 * @return the style
	 */
	public String getStyle() {
		return style;
	}

	/**
	 * @param style the style to set
	 */
	public void setStyle(String style) {
		this.style = style;
	}
	
	
	
	/**
	 * @return the adapterClassName
	 */
	public String getAdapterClassName() {
		return adapterClassName;
	}


	/**
	 * @param adapterClassName the adapterClassName to set
	 */
	public void setAdapterClassName(String adapterClassName) {
		this.adapterClassName = adapterClassName;
	}


	/**
	 * @return the adapterName
	 */
	public String getAdapterName() {
		return adapterName;
	}


	/**
	 * @param adapterName the adapterName to set
	 */
	public void setAdapterName(String adapterName) {
		this.adapterName = adapterName;
	}
	


	/**
	 * @return the match
	 */
	public String getMatch() {
		return match;
	}



	/**
	 * @param match the match to set
	 */
	public void setMatch(String match) {
		this.match = match;
	}



	/**
	 * @return the staticInvoke
	 */
	public boolean isStaticInvoke() {
		return staticInvoke;
	}



	/**
	 * @param staticInvoke the staticInvoke to set
	 */
	public void setStaticInvoke(boolean staticInvoke) {
		this.staticInvoke = staticInvoke;
	}



	/**
	 * @return the serviceMethod
	 */
	public Method getServiceMethod() {
		return serviceMethod;
	}


	/**
	 * @return the componentMethod
	 */
	public Method getComponentMethod() {
		return componentMethod;
	}





	/**
	 * 
	 * @author janly
	 *
	 */
	class Method{
		private String methodName;
		private String pattern;
		private String match;
		private final java.util.List args=new java.util.ArrayList();
		private final java.util.List rets=new java.util.ArrayList();
		private final java.util.List exps=new java.util.ArrayList();
		
		
		public void clearExps(){
			this.exps.clear();
		}
		
		private String convertArgsToPattern(){
			if(methodName==null) return null;
			if(this.rets.isEmpty()) return null;
			
			java.lang.StringBuffer sb=new java.lang.StringBuffer("(");
			for(java.util.Iterator it=this.args.iterator();it.hasNext();){
				sb.append(Config.converToPattern(it.next().toString()));
			}
			sb.append(")");
			
			for(java.util.Iterator it=this.rets.iterator();it.hasNext();){
				sb.append(Config.converToPattern(it.next().toString()));
			}

			return sb.toString();
		}	
		
		public String[] getExceptions(){
			return (String[])this.exps.toArray(new String[]{});
		}
		
		boolean addArg(String arg){
			return args.add(arg.replace('.', '/'));
		}
		
		boolean addRet(String ret){
			return rets.add(ret.replace('.', '/'));
		}
		
		boolean addExp(String exp){
			return exps.add(exp.replace('.', '/'));
		}
		
		/**
		 * @return the pattern
		 */
		public String getPattern() {
			return pattern;
		}
		/**
		 * @param pattern the pattern to set
		 */
		public void setPattern(String pattern) {
			this.pattern = pattern;
			this.args.clear();
			this.rets.clear();
			Type[] argsType=Type.getArgumentTypes(pattern);
			Type retsType=Type.getReturnType(pattern);
			for(int i=0;i<argsType.length;i++){
				this.args.add(argsType[i].getClassName());
			}
			this.rets.add(retsType.getClassName());
		}
		/**
		 * @return the methodName
		 */
		public String getMethodName() {
			return methodName;
		}
		/**
		 * @param methodName the methodName to set
		 */
		public void setMethodName(String methodName) {
			this.methodName = methodName;
		}
		/**
		 * @return the descriptor
		 */
		public String getDescriptor() {
			if(this.pattern!=null) return this.pattern;
			return this.convertArgsToPattern();
		}

		/**
		 * @return the args
		 */
		public java.util.List getArgs() {
			return args;
		}

		/**
		 * @return the rets
		 */
		public java.util.List getRets() {
			return rets;
		}

		/**
		 * @return the exps
		 */
		public java.util.List getExps() {
			return exps;
		}
		
		
		

		/**
		 * @return the match
		 */
		public String getMatch() {
			if(this.match==null) return Config.this.getMatch();
			return match;
		}

		/**
		 * @param match the match to set
		 */
		public void setMatch(String match) {
			this.match = match;
		}
	
		
	}

}

5.提供WebLogic服务器的实现
/**
 * 
 */
package org.youisoft.oracle;
import java.util.Hashtable;
import org.youisoft.config.Config;
import org.youisoft.config.Configs;
import org.youisoft.config.XmlConfig;

import weblogic.utils.classloaders.ClassPreProcessor;

/**
 * @author janly
 *
 */
public class ServiceClassPreProcessor implements ClassPreProcessor {
	private class KeyListMap{
		private java.util.Map innerMap=new java.util.HashMap();

		/* (non-Javadoc)
		 * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
		 */
		public Object put(Object arg0, Object arg1) {
			if(this.innerMap.get(arg0)==null){
				java.util.List list=new java.util.ArrayList();
				list.add(arg1);
				this.innerMap.put(arg0,list);
			}else{
				((java.util.List)this.innerMap.get(arg0)).add(arg1);
			}
			
			return arg1;
		}

		/* (non-Javadoc)
		 * @see java.util.HashMap#get(java.lang.Object)
		 */
		public Object get(Object key) {
			return this.innerMap.get(key);
		}
		
		
		
		
		
	}
	public final static String XMLCONFIG="youisoft.service.config";
	
	
	//-Dweblogic.classloader.preprocessor=org.youisoft.oracle.ServiceClassPreProcessor
	private KeyListMap serviceMap=new KeyListMap();

	/* (non-Javadoc)
	 * @see weblogic.utils.classloaders.ClassPreProcessor#initialize(java.util.Hashtable)
	 */
	public void initialize(Hashtable arg0) {

		
		String configFileName=null;
		if(arg0!=null&&arg0.get(XMLCONFIG)!=null){
			configFileName=arg0.get(XMLCONFIG).toString();
		}
		if(System.getProperty(XMLCONFIG)!=null){
			configFileName=System.getProperty(XMLCONFIG);
		}
		try{
			java.io.FileInputStream fis=new java.io.FileInputStream(configFileName);
			org.xml.sax.InputSource inputSource=new org.xml.sax.InputSource(fis);
			Configs obj=(Configs)XmlConfig.parserXml(inputSource);
			for(int i=0;obj.getConfigs()!=null&&i<obj.getConfigs().length;i++){
				this.serviceMap.put(obj.getConfigs()[i].getServiceClassName().replace('/', '.'), obj.getConfigs()[i]);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	/* (non-Javadoc)
	 * @see weblogic.utils.classloaders.ClassPreProcessor#preProcess(java.lang.String, byte[])
	 */
	public byte[] preProcess(String arg0, byte[] arg1) {
		if(this.serviceMap.get(arg0)!=null){
			try{
				java.util.List list=(java.util.List)this.serviceMap.get(arg0);
				for(java.util.Iterator it=list.iterator();it.hasNext();){
					Config config=(Config)it.next();
					arg1=config.config(arg1);
				}
				
			}catch(java.lang.Throwable t){
				
			}
		
		}

		return arg1;
	}
	

}
0
0
分享到:
评论

相关推荐

    AOP 的利器 ASM 3.0

    本文将详细介绍一种轻量级的Java字节码操控框架——ASM 3.0,并探讨其如何帮助实现AOP。 #### 什么是ASM? ASM是一个用于动态生成或增强现有Java类的字节码操控框架。它可以被用来直接修改`.class`文件,也可以在...

    ASM函数监听实现(三)拦截注入函数的参数值 (函数执行前)

    ASM库是一个轻量级的Java字节码操控和分析框架,常用于动态代理、代码生成以及AOP实现。本篇文章将深入探讨如何使用ASM库来实现函数监听,特别是如何在函数执行前拦截并改变其参数值。 首先,我们需要理解ASM库的...

    cglib-2.2.jar asm-tree.jar asm-commons.jar asm.jar

    **ASM** 是一个轻量级的字节码处理库,它允许用户在运行时动态生成类和接口,或者修改已有的类。ASM.jar包含了ASM库的所有核心类,这些类可以解析和生成Java字节码,从而实现对Java类的低级别操作。 **ASM-Commons*...

    asm-bo-0.3.5.zip

    开发者可以利用ASM来实现诸如AOP框架、代码生成工具、性能分析器等功能。 总的来说,ASM BYTECODE OUTLINE插件是Android Studio中一个强大的辅助工具,它结合了ASM库的强大功能,提供了直观的字节码查看界面,有助...

    asm-2.2.3.jar,asm-commons-2.2.3.jar,asm-util-2.2.3.jar,cglib-nodep-2.1_3.jar

    ASM是一个轻量级的Java字节码操控和分析框架,而CGLIB是一个强大的代码生成库,它在许多情况下作为Spring框架的依赖用于AOP(面向切面编程)。 首先,我们来看ASM库。ASM-2.2.3.jar、asm-commons-2.2.3.jar和asm-...

    org.springframework.asm-3.0.5.RELEASE.jar

    ASM是一个轻量级的Java字节码操控和分析框架,它可以直接生成和读取Java类的字节码。ASM提供了一种低级别的接口,允许开发者创建、修改和分析类或对象。在Spring框架中,ASM主要用于AOP(面向切面编程)的实现,例如...

    aop的jar包.rar

    可能还有cglib-nodep.jar,这是一个轻量级的字节码库,用于生成代理类。还可能包括asm.jar,这是一个用于读写Java字节码的库,Spring AOP在使用CGLIB代理时可能会用到。 总之,AOP提供了一种有效处理系统中横切关注...

    asm-3.1.jar

    此外,社区还提供了许多基于ASM的开源项目,如CGLIB(一个代码生成库,用于创建子类和动态代理)和Aspectran(一个基于AOP的轻量级服务框架)。 总之,ASM-3.1.jar是一个强大的工具,它允许开发者深入到Java字节码...

    Spring框架 一个AOP程序.zip

    Spring框架是Java开发中最常用的轻量级框架之一,它的核心特性包括依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。本压缩包中的资源着重于Spring框架的AOP部分,这是一...

    SpringMVC3.0-Jar全量包含cglib几个包-aop的aspectj几个包

    8. **common-logging**:这是一个轻量级的日志抽象层,允许开发者选择不同的日志实现,如Log4j、java.util.logging或commons-logging自身。Spring使用它来记录框架内部的信息,方便开发者调整日志级别和选择合适的...

    asm-all-3.3

    3. **轻量级**:ASM库的体积相对较小,且无需额外的运行时依赖,易于集成到项目中。 然而,ASM也有一定的学习曲线,因为它涉及到对Java字节码和JVM内部机制的深入理解。但是,一旦掌握了基本用法,ASM就能够成为...

    ASM中文帮助文档

    ASM是一个轻量级的库,提供了对Java字节码的低级别访问。它能够直接操作字节码,从而可以用于创建、加载或修改类。ASM提供了两种主要的API:ClassWriter用于生成字节码,而ClassReader则用于解析已存在的字节码。 ...

    cglib.jar | asm.jar对应版本

    它是一个轻量级的Java字节码操控和分析框架,可以直接生成和修改Java类文件的字节码。在cglib中,asm库用于动态生成字节码,帮助我们创建目标类的子类。ASM提供了一套API,可以直接操作字节码,实现对类的增强,如...

    asm-all-4.0.jar.zip

    6. **性能**:由于其轻量级的设计,ASM在处理字节码时具有较高的性能,尤其在大量生成或分析类时,效率表现优秀。 使用ASM时,你需要了解基本的字节码概念,如常量池、操作码、栈映射表等,并熟悉ASM提供的类和接口...

    cglib_2.2.2 动态代理jar包(包含asm_3.3.1)

    - ASM是一个轻量级的字节码操作和分析框架,它可以直接生成和修改Java类的字节码。 - 在CGLIB中,ASM负责生成和修改字节码,创建目标类的子类,以及在子类中插入额外的代码,实现方法拦截。 4. **CGLIB的优缺点**...

    asm-tree-1.5.3.jar.zip

    同时,由于ASM Tree库是一个轻量级的库,它的性能表现良好,非常适合在内存有限或者对性能要求高的环境中使用。 为了有效地使用ASM Tree库1.5.3.jar,开发者需要了解Java字节码的相关知识,包括类文件结构、操作码...

    asm-xml-20041228.180559.jar.zip

    4. **轻量级**:ASM的设计目标之一是小巧且高效,这使得它在资源有限的环境中也能良好工作。 接下来,我们关注"asm-xml-20041228.180559.jar"。这个文件名暗示了ASM库的一个版本可能被扩展或集成了XML处理能力。XML...

    asm-1.5.2.jar.zip

    例如,Spring AOP框架就利用ASM来生成代理类以实现切面逻辑。同时,由于ASM的性能优秀且小巧,它也是许多轻量级库的首选。 综上所述,"asm-1.5.2.jar.zip"是一个包含ASM 1.5.2版本的JAR文件和许可证信息的压缩包,...

    spring aop操作的基本jar包

    7. `asm*.jar` (例如:asm-7.1.jar): 这些是ASM库的版本,ASM是一个轻量级的Java字节码操控和分析框架,Spring使用它来实现动态代理和织入切面。 8. `cglib-nodep.jar`: 有时,Spring会使用CGLIB作为动态代理的实现...

    Struts2源码(xwork|asm|commons|freemark|ognl)

    XWork框架提供了一种轻量级的、基于Action的模型,支持拦截器和类型转换,使得业务处理更加灵活和模块化。它的Action接口和ActionSupport类是开发者编写业务逻辑的入口,而Interceptor(拦截器)则允许在Action执行...

Global site tag (gtag.js) - Google Analytics