从服务端转到Android,最大的遗憾是不能用绿色健康的Spring了。

虽然依稀记得有spring for android,但是看了官网才发现根本没有IOC 和 AOP这些功能,只有http客户端功能

大失所望之下,自己动手搞了个最简单的demo,遂有创建个开源项目android下的spring的念头...

诸君可能会大大拍砖 性能啦之类的 确实值得考虑,但是随着Android项目日益庞大,代码量稳步上升,结构越来越混乱,

维护成本也越来越高,相比之下使用Spring的服务端好很多。有兴趣的看看demo代码吧


android-spring 项目:(作为android lib 项目)

项目地址: https://code.google.com/p/spring-android/


package android.springframework;/** * Bean上下文 */public interface BeanContext {String tag = "springframework";<T> T getBean(Class<T> clazz);<T> T getBean(String name, Class<T> clazz);Object getBean(String name);}

package android.springframework;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 组件注解 * */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Component {String name() default "";boolean prototype() default true;}

package android.springframework;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * Resource 注入注解<p> * 目前只支持字段 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Resource {String name() default "";}
/** *  */package android.springframework;import static org.ow2.asmdex.Opcodes.*;import java.io.InputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.net.URL;import java.util.HashMap;import java.util.zip.ZipEntry;import java.util.zip.ZipFile;import org.ow2.asmdex.AnnotationVisitor;import org.ow2.asmdex.ApplicationReader;import org.ow2.asmdex.ApplicationVisitor;import org.ow2.asmdex.ClassVisitor;import org.ow2.asmdex.FieldVisitor;import android.content.Context;import android.util.Log;/** * 基于注解的BeanContext * */public class AnnotaionBeanContext implements BeanContext {/** * 类扫描的基础包 */private final String basePkgToScan;private HashMap<String, Object> namedBeans = new HashMap<String, Object>();private HashMap<Class, Object> classBeans = new HashMap<Class, Object>();private HashMap<String, Class> descToClass = new HashMap<String, Class>();/** * Android Application Context - 供所有使用Context的非Android组件类公共使用 */private final Context context;private static final String COMPONNET_ANNO_DESC = "Landroid/springframework/Component;";private static final String RESOURCE_ANNO_DESC = "Landroid/springframework/Resource;";private static final int API_ASM = ASM4;public AnnotaionBeanContext(String basePkgToScan, Context context) {Log.d(tag, "AnnotaionBeanContext 初始化 ");this.basePkgToScan = basePkgToScan;this.context = context;try {initApplication();} catch (Exception e) {Log.e(tag, Log.getStackTraceString(e));}}private void initApplication() throws Exception {URL moduleResUrl = AnnotaionBeanContext.class.getClassLoader().getResource("AndroidManifest.xml");String path = moduleResUrl.getFile();String apkPath = path.substring(path.indexOf('/'), path.indexOf("!/"));Log.d(tag, "apkPath = " + apkPath);ZipFile zipFile = new ZipFile(apkPath);ZipEntry classesEntry = zipFile.getEntry("classes.dex");InputStream classesStream = zipFile.getInputStream(classesEntry);ApplicationReader ar = new ApplicationReader(API_ASM, classesStream);AppVisitor appVistor = new AppVisitor();appVistor.setModulePackage(basePkgToScan);ar.accept(appVistor, 0);classesStream.close();zipFile.close();}@SuppressWarnings("unchecked")@Overridepublic <T> T getBean(Class<T> clazz) {return (T) classBeans.get(clazz);}@Overridepublic <T> T getBean(String name, Class<T> clazz) {// TODO Auto-generated method stubreturn null;}@Overridepublic Object getBean(String name) {// TODO Auto-generated method stubreturn null;}class AppVisitor extends ApplicationVisitor {private String modulePackage;private BeanClassVisitor beanClassVisitor = new BeanClassVisitor(api);public AppVisitor() {super(API_ASM);}public void setModulePackage(String modulePackage) {if (modulePackage.startsWith("L")) {this.modulePackage = modulePackage;} else {this.modulePackage = 'L' + modulePackage.replace('.', '/');}}@Overridepublic ClassVisitor visitClass(int access, String name,String[] signature, String superName, String[] interfaces) {if (name.startsWith(modulePackage)) {return beanClassVisitor;}return null;}}class BeanClassVisitor extends ClassVisitor {public BeanClassVisitor(int api) {super(api);}String className;BeanFieldVistor beanFieldVistor = new BeanFieldVistor();boolean isComponent;Object bean;@Overridepublic void visit(int version, int access, String name,String[] signature, String superName, String[] interfaces) {Log.i(tag, "*** className = " + name);className = name;beanFieldVistor.reset();}@Overridepublic AnnotationVisitor visitAnnotation(String desc, boolean visible) {Log.i(tag, "@Annotation : desc = " + desc + ", visible = "+ visible);if (COMPONNET_ANNO_DESC.equals(desc)) {isComponent = true;bean = initBean(className);// for (Field f : bean.getClass().getDeclaredFields()) {// Resource resAnn = f.getAnnotation(Resource.class);// if (resAnn == null) {// continue;// }// f.setAccessible(true);// Object fval = initBean(f.getType());// if (fval != null) {// try {// f.set(bean, fval);// } catch (Exception e) {// e.printStackTrace();// }// }// }}return null;}@Overridepublic FieldVisitor visitField(int access, String name, String desc,String[] signature, Object value) {if (isComponent) {beanFieldVistor.set(bean, access, name, desc, signature);return beanFieldVistor;}return null;}}class BeanFieldVistor extends FieldVisitor {public BeanFieldVistor() {super(API_ASM);}void reset() {access = 0;fieldName = "";fieldDesc = "";signature = null;ownerBean = null;}int access;String fieldName;String fieldDesc;String[] signature;Object ownerBean;void set(Object bean, int access, String name, String desc,String[] signature) {this.ownerBean = bean;this.access = access;this.fieldName = name;this.fieldDesc = desc;this.signature = signature;}@Overridepublic AnnotationVisitor visitAnnotation(String desc, boolean visible) {if (RESOURCE_ANNO_DESC.equals(desc)) {try {Field field = ownerBean.getClass().getDeclaredField(fieldName);field.setAccessible(true);Object fval = initBean(field.getType());if (fval != null) {field.set(ownerBean, fval);}} catch (Exception e) {e.printStackTrace();}}return super.visitAnnotation(desc, visible);}}private Object initBean(String className) {if (className.endsWith(";")) {className = className.substring(1, className.length() - 1);}if (className.contains("/")) {className = className.replace('/', '.');}Object ins = null;Class<?> clazz = descToClass.get(className);if (clazz == null) {try {return initBean(clazz = Class.forName(className));} catch (Exception e) {Log.e(tag, Log.getStackTraceString(e));}} else {ins = classBeans.get(clazz);}return ins;}private Object initBean(Class<?> clazz) {if (clazz == null) {return null;}Object ins = classBeans.get(clazz);if (ins != null) {return ins;}descToClass.put(clazz.getName(), clazz);try {Constructor<?> defCons = clazz.getConstructor();ins = defCons.newInstance();classBeans.put(clazz, ins);} catch (NoSuchMethodException e) {try {Constructor<?> cons = clazz.getConstructor(Context.class);ins = cons.newInstance(context);classBeans.put(clazz, ins);} catch (Exception e1) {Log.e(tag, Log.getStackTraceString(e1));}} catch (Exception e) {Log.e(tag, Log.getStackTraceString(e));}return ins;}}
项目依赖了ASMdex, 下载地址为:http://download.forge.ow2.org/asm/asmdex-1.0.jar

清单文件为空即可(AndroidManifest.xml):

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="android.springframework"    android:versionCode="1"    android:versionName="1.0" ></manifest>
project.properties:
# Project target.target=android-19android.library=true

一个简单的Spring android 实现完事,下面是一个demo项目,依赖spring-android项目


package springdemo.modules.app;import android.content.Context;import android.springframework.Component;/** * */@Componentpublic class AppManager {private Context context;public AppManager(Context context) {this.context = context;}public String getApps() {String apps = "apps:" + context.getPackageName() + ";com.facebook";return apps;}}
package springdemo.modules.push;import springdemo.modules.app.AppManager;import android.springframework.Component;import android.springframework.Resource;/** * */@Componentpublic class PushManager {@Resourceprivate AppManager appManager;public String push() {return "push: appManager.getApps()=" + appManager.getApps();}}


package springdemo;import android.content.Context;import android.springframework.AnnotaionBeanContext;import android.springframework.BeanContext;/** * */public class SpringApplicationHelper {private BeanContext beanContext;private Context context;private SpringApplicationHelper(Context context) {Context applicationCtx = context.getApplicationContext();beanContext = new AnnotaionBeanContext(getClass().getPackage().getName() + ".modules", applicationCtx);this.context = applicationCtx;}private static SpringApplicationHelper instance;public static SpringApplicationHelper getInstance(Context context) {if (instance == null && context != null) {instance = new SpringApplicationHelper(context);}return instance;}public BeanContext getBeanContext() {return beanContext;}}

package spring.android.demo;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.View;import spring.android.demo.R;import springdemo.SpringApplicationHelper;import springdemo.modules.push.PushManager;public class MainActivity extends Activity {private static final String tag = "spring-test";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);findViewById(R.id.btn_spring_test).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {testSpringBean_pushMgr();} catch (Throwable e) {Log.e(tag, Log.getStackTraceString(e));}}});}    private void testSpringBean_pushMgr(){    SpringApplicationHelper springHelper = SpringApplicationHelper.getInstance(MainActivity.this);PushManager pushManager = springHelper.getBeanContext().getBean(PushManager.class);String msg = "pushManager.push() = "+ pushManager.push();Log.i(tag, msg);    }}

布局文件(main/layout.xml):

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >        <Button        android:id="@+id/btn_spring_test"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/btn_text" /></LinearLayout>

project.properties文件:

# Project target.target=android-19android.library.reference.1=../spring-android

AndroidManifest.xml 文件:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="spring.android.demo"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="10"        android:targetSdkVersion="19" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        >        <activity            android:name="spring.android.demo.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>


界面效果:


日志输出结果:

11-09 20:14:46.566: I/springframework(12149): *** className = Lspringdemo/modules/app/AppManager;
11-09 20:14:46.566: I/springframework(12149): @Annotation : desc = Landroid/springframework/Component;, visible = true
11-09 20:14:46.566: I/springframework(12149): *** className = Lspringdemo/modules/push/PushManager;
11-09 20:14:46.566: I/springframework(12149): @Annotation : desc = Landroid/springframework/Component;, visible = true
11-09 20:14:46.576: I/spring-test(12149): pushManager.push() = push: appManager.getApps()=apps:spring.android.demo;com.facebook

更多相关文章

  1. 浅入浅出 Android(安卓)安全:第三章 Android(安卓)本地用户空间层
  2. Android(安卓)串口通讯-------android -serialport-api
  3. android 操作sdcard中的多媒体文件(一)——音乐列表的制作
  4. Android系列教程之Android项目的目录结构
  5. android资源
  6. 使用Maven管理Android项目(一)
  7. Android中的资源与国际化
  8. Android(安卓)sdk 软件栈
  9. NPM 和webpack 的基础使用

随机推荐

  1. SQL Server 2008 到底需要使用哪些端口?
  2. sqlserver 存储过程带事务 拼接id 返回值
  3. SQL语句实例说明 方便学习mysql的朋友
  4. 使用SSIS创建同步数据库数据任务的方法
  5. CPQuery 解决拼接SQL的新方法
  6. 编程经验点滴 动态SQL的拼接技巧
  7. MSSQL2005数据附加失败报错3456解决办法
  8. sqlserver CONVERT()函数用法小结
  9. SQL Server 高性能写入的一些经验总结
  10. 磁盘缓存专题之一 缓存命中和缓存未命中&