Browse Source

jfinal 3.5

James 7 years ago
parent
commit
75f4e6ba76

+ 149 - 0
src/main/java/com/jfinal/aop/Aop.java

@@ -0,0 +1,149 @@
+package com.jfinal.aop;
+
+/**
+ * Aop 支持在任意时空便捷使用 Aop
+ * 
+ * Aop 主要功能:
+ * 1:Aop.get(Class) 根据 Class 去创建对象,然后对创建好的对象进行依赖注入
+ * 
+ * 2:Aop.inject(Object) 对传入的对象进行依赖注入
+ * 
+ * 3:Aop.inject(...) 与 Aop.get(...) 的区别是前者只针对传入的对象之中的属性进行注入。
+ *    而后者先要使用 Class 去创建对象,创建完对象以后对该对象之中的属性进行注入。
+ *    简单一句话:get(...) 比 inject(...) 多了一个对象创建的过程
+ *    
+ * 4:是否要 enhance 与 singleton 根据 Aop.setEhnace(...)、Aop.setSingleton(...) 配置来操作
+ * 
+ * 5:在 @Inject(...) 指定 enhance 与 singleton 的配置可以覆盖掉默认配置
+ * 
+ * 
+ * 基本用法:
+ * 1:先定义业务
+ *    public class Service {
+ *       @Inject
+ *       OtherService otherSrv;
+ *       
+ *       @Before(Aaa.class)
+ *       public void doIt() {
+ *          ...
+ *       }
+ *    }
+ *    
+ *    public class OtherService {
+ *       @Before(Bbb.class)
+ *       public void doOther() {
+ *          ...
+ *       }
+ *    }
+ *    
+ * 
+ * 2:只进行注入,对象自己创建
+ *    Service srv = Aop.inject(new Service());
+ *    srv.doIt();
+ *    Aop.injectd(...) 会对 OtherService otherSrv 进行注入,并且对 otherSrv 进行 ehnace,
+ *    所以 OtherService.doOther() 方法上的 Bbb 拦截器会生效
+ *    
+ * 3:创建对象并注入
+ *    Service srv = Aop.get(Service.class);
+ *    srv.doIt();
+ *    Aop.get(...) 用法对 OtherService otherSrv 的处理方式完全一样,在此基础之上 Service 自身也会被
+ *    enhance,所以 doIt() 上的 Aaa 拦截器会生效,而 Aop.inject(...) 用法下 Aaa 拦截器不起用用
+ * 
+ * 4:以上两点中的 enhance 还取决于配置
+ *    Aop.setEnhance(false) 配置以后,只注入对象,但被注入对象不进行 enhance, Aaa、Bbb 拦截器都不会生效
+ *    
+ * 
+ * 
+ * 
+ * 高级用法:
+ * 1:@Inject 注解默认注入属性自身类型的对象,可以通过如下代码指定被注入的类型:
+ *    @Inject(UserServiceImpl.class)			// 此处的 UserServiceImpl 为 UserService 的子类或实现类
+ *    UserService userService;
+ * 
+ * 2:被注入对象默认会被 enhance 增强,可以通过 Aop.setEnhance(false) 配置默认不增强
+ * 
+ * 3:被注入对象默认是 singleton 单例,可以通过 Aop.setSingleton(false) 配置默认不为单例
+ * 
+ * 4:可以在 @Inject 注解中直接配置 enhance 增强与 singleton 单例:
+ *    @Inject(enhance=YesOrNo.NO, singleton=YesOrNo.YES)
+ *    注意:如上在 @Inject 直接配置会覆盖掉 2、3 中 setEnhance()/setSingleton() 方法配置的默认值
+ * 
+ * 5:如上 2、3、4 中的配置,建议的用法是:先用 setEnhance()/setSingleton() 配置大多数情况,然后在个别
+ *    违反上述配置的情况下在 @Inject 中直接 enhance、singleton 来覆盖默认配置,这样可以节省大量代码
+ */
+public class Aop {
+	
+	private static AopProxy aopProxy = new AopProxy();
+	
+	public static <T> T get(Class<T> targetClass) {
+		return aopProxy.get(targetClass);
+	}
+	
+	public static <T> T inject(T targetObject) {
+		return aopProxy.inject(targetObject);
+	}
+	
+	public static <T> T inject(T targetObject, int injectDepth) {
+		return aopProxy.inject(targetObject, injectDepth);
+	}
+	
+	/* 通过 Aop.getAopProxy().inject(...) 可调用如下两个方法,不直接开放出来
+	public static void inject(Class<?> targetClass, Object targetObject) throws ReflectiveOperationException {
+		aopProxy.inject(targetClass, targetObject);
+	}
+	
+	public static void inject(Class<?> targetClass, Object targetObject, int injectDepth) throws ReflectiveOperationException {
+		aopProxy.inject(targetClass, targetObject, injectDepth);
+	}*/
+	
+	/**
+	 * 设置 AopProxy,便于扩展自己的 AopProxy 实现
+	 */
+	public static void setAopProxy(AopProxy aopProxy) {
+		if (aopProxy == null) {
+			throw new IllegalArgumentException("aopProxy can not be null");
+		}
+		Aop.aopProxy = aopProxy;
+	}
+	
+	public static AopProxy getAopProxy() {
+		return aopProxy;
+	}
+	
+	/**
+	 * 设置被注入的对象是否被增强,可使用 @Inject(enhance = YesOrNo.NO) 覆盖此默认值
+	 */
+	public static void setEnhance(boolean enhance) {
+		aopProxy.setEnhance(enhance);
+	}
+	
+	public static boolean isEnhance() {
+		return aopProxy.isEnhance();
+	}
+	
+	/**
+	 * 设置被注入的对象是否为单例,可使用 @Inject(singleton = YesOrNo.NO) 覆盖此默认值 
+	 */
+	public static void setSingleton(boolean singleton) {
+		aopProxy.setSingleton(singleton);
+	}
+	
+	public static boolean isSingleton() {
+		return aopProxy.isSingleton();
+	}
+	
+	/**
+	 * 设置注入深度,避免被注入类在具有循环依赖时造成无限循环
+	 */
+	public static void setInjectDepth(int injectDepth) {
+		aopProxy.setInjectDepth(injectDepth);
+	}
+	
+	public static int getInjectDepth() {
+		return aopProxy.getInjectDepth();
+	}
+}
+
+
+
+

+ 80 - 0
src/main/java/com/jfinal/aop/AopControllerFactory.java

@@ -0,0 +1,80 @@
+package com.jfinal.aop;
+
+import com.jfinal.core.Controller;
+import com.jfinal.core.ControllerFactory;
+
+/**
+ * AopControllerFactory 用于注入依赖对象并更好支持 AOP,其优点如下:
+ * 1:使用 @Inject 自动化注入并 enhance 对象,免去业务层 AOP 必须手动 enhance 的步骤
+ * 
+ * 2:免去业务层维护单例的样板式代码,例如下面代码可以删掉了:
+ *    public static final MyService me = new MyService();
+ * 
+ * 
+ * 基本用法如下:
+ * 1:配置
+ *    me.setControllerFactory(new AopControllerFactory());
+ *    
+ * 2:Controller 中注入业务层,也可以注入任何其它类,不一定非得是 Service
+ *    public class MyController extends Controller {
+ *    
+ *       @Inject
+ *       MyService service;
+ *       
+ *       public void index() {
+ *          render(service.doIt());
+ *       }
+ *    }
+ *    
+ * 3:Service 注入另一个 Service,也可以注入任何其它类,不一定非得是 Service
+ *    public class MyService {
+ *    
+ *       @Inject
+ *       OtherService other;		// OtherService 内部还可以继续接着注入
+ *       
+ *       public void doIt() {
+ *          other.doOther();
+ *       }
+ *    }
+ * 
+ * 4:AopControllerFactory 默认处理了从 Controller 为源头的依赖与注入链条,如果希望在拦截器
+ *    使用注入功能,可以使用如下的方式:
+ *    public class MyInterceptor implements Interceptor {
+ *      
+ *       MyService srv = Aop.get(MyService.class);
+ *       
+ *       public void intercept(Invocation inv) {
+ *          srv.doIt();
+ *       }
+ *    }
+ * 
+ * 
+ * 高级用法:
+ * 1:@Inject 注解默认注入属性自身类型的对象,可以通过如下代码指定被注入的类型:
+ *    @Inject(UserServiceImpl.class)			// 此处的 UserServiceImpl 为 UserService 的子类或实现类
+ *    UserService userService;
+ * 
+ * 2:被注入对象默认会被 enhance 增强,可以通过 Aop.setEnhance(false) 配置默认不增强
+ * 
+ * 3:被注入对象默认是 singleton 单例,可以通过 Aop.setSingleton(false) 配置默认不为单例
+ * 
+ * 4:可以在 @Inject 注解中直接配置 enhance 增强与 singleton 单例:
+ *    @Inject(enhance=YesOrNo.NO, singleton=YesOrNo.YES)
+ *    注意:如上在 @Inject 直接配置会覆盖掉 2、3 中 setEnhance()/setSingleton() 方法配置的默认值
+ * 
+ * 5:如上 2、3、4 中的配置,建议的用法是:先用 setEnhance()/setSingleton() 配置大多数情况,然后在个别
+ *    违反上述配置的情况下在 @Inject 中直接 enhance、singleton 来覆盖默认配置,这样可以节省大量代码
+ */
+public class AopControllerFactory extends ControllerFactory {
+	
+	@Override
+	public Controller getController(Class<? extends Controller> controllerClass) throws ReflectiveOperationException {
+		Controller c = controllerClass.newInstance();
+		// Aop.getAopProxy().inject((Class)controllerClass, c);
+		return Aop.inject(c);
+	}
+}
+
+
+
+

+ 212 - 0
src/main/java/com/jfinal/aop/AopProxy.java

@@ -0,0 +1,212 @@
+package com.jfinal.aop;
+
+import java.lang.reflect.Field;
+import java.util.concurrent.ConcurrentHashMap;
+import com.jfinal.aop.Enhancer;
+
+/**
+ * AopProxy 是工具类 Aop 功能的具体实现,详细用法见 Aop
+ */
+public class AopProxy {
+	
+	// 单例缓存
+	protected ConcurrentHashMap<Class<?>, Object> singletonCache = new ConcurrentHashMap<Class<?>, Object>();
+	
+	protected static int MAX_INJECT_DEPTH = 7;			// 最大注入深度 
+	
+	protected YesOrNo enhance = YesOrNo.YES;				// 默认增强
+	protected YesOrNo singleton = YesOrNo.YES;			// 默认单例
+	protected int injectDepth = 3;						// 默认注入深度
+	
+	@SuppressWarnings("unchecked")
+	public <T> T get(Class<T> targetClass) {
+		try {
+			// Aop.get(obj.getClass()) 可以用 Aop.inject(obj),所以注掉下一行代码 
+			// targetClass = (Class<T>)getUsefulClass(targetClass);
+			
+			Object ret;
+			if (singleton == YesOrNo.NO) {
+				ret = createObject(targetClass, enhance);
+				inject(targetClass, ret, injectDepth);
+				return (T)ret;
+			}
+			
+			ret = singletonCache.get(targetClass);
+			if (ret == null) {
+				synchronized (targetClass) {
+					ret = singletonCache.get(targetClass);
+					if (ret == null) {
+						ret = createObject(targetClass, enhance);
+						inject(targetClass, ret, injectDepth);
+						singletonCache.put(targetClass, ret);
+					}
+				}
+			}
+			return (T)ret;
+		}
+		catch (ReflectiveOperationException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	public <T> T inject(T targetObject) {
+		try {
+			inject(targetObject.getClass(), targetObject, injectDepth);
+			return targetObject;
+		} catch (ReflectiveOperationException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	public <T> T inject(T targetObject, int injectDepth) {
+		try {
+			inject(targetObject.getClass(), targetObject, injectDepth);
+			return targetObject;
+		} catch (ReflectiveOperationException e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	public <T> T inject(Class<T> targetClass, T targetObject) throws ReflectiveOperationException {
+		inject(targetClass, targetObject, injectDepth);
+		return targetObject;
+	}
+	
+	public void inject(Class<?> targetClass, Object targetObject, int injectDepth) throws ReflectiveOperationException {
+		if ((injectDepth--) <= 0) {
+			return ;
+		}
+		
+		targetClass = getUsefulClass(targetClass);
+		Field[] fields = targetClass.getDeclaredFields();
+		if (fields.length == 0) {
+			return ;
+		}
+		
+		for (Field field : fields) {
+			Inject inject = field.getAnnotation(Inject.class);
+			if (inject == null) {
+				continue ;
+			}
+			
+			Class<?> fieldInjectedClass = inject.value();
+			if (fieldInjectedClass == Void.class) {
+				fieldInjectedClass = field.getType();
+			}
+			
+			YesOrNo enhance = inject.enhance();
+			if (enhance == YesOrNo.DEFAULT) {
+				enhance = this.enhance;
+			}
+			
+			YesOrNo singleton = inject.singleton();
+			if (singleton == YesOrNo.DEFAULT) {
+				singleton = this.singleton;
+			}
+			
+			Object fieldInjectedObject = getOrCreateObject(fieldInjectedClass, enhance, singleton);
+			field.setAccessible(true);
+			field.set(targetObject, fieldInjectedObject);
+			
+			// 递归调用,为当前被注入的对象进行注入
+			this.inject(fieldInjectedObject.getClass(), fieldInjectedObject, injectDepth);
+		}
+	}
+	
+	protected Object getOrCreateObject(Class<?> targetClass, YesOrNo enhance, YesOrNo singleton) throws ReflectiveOperationException {
+		if (singleton == YesOrNo.NO) {
+			return createObject(targetClass, enhance);
+		}
+		
+		Object ret = singletonCache.get(targetClass);
+		if (ret == null) {
+			synchronized (targetClass) {
+				ret = singletonCache.get(targetClass);
+				if (ret == null) {
+					ret = createObject(targetClass, enhance);
+					singletonCache.put(targetClass, ret);
+				}
+			}
+		}
+		
+		return ret;
+	}
+	
+	/**
+	 * 由于上层已经处理过 singleton,所以 Enhancer.enhance() 方法中不必关心 singleton
+	 */
+	protected Object createObject(Class<?> targetClass, YesOrNo enhance) throws ReflectiveOperationException {
+		return (enhance == YesOrNo.YES) ? Enhancer.enhance(targetClass) : targetClass.newInstance();
+	}
+	
+	/**
+	 * 被 cglib、guice 增强过的类需要通过本方法获取到被增强之前的类型
+	 * 否则调用其 targetClass.getDeclaredFields() 方法时
+	 * 获取到的是一堆 cglib guice 生成类中的 Field 对象
+	 * 而被增强前的原类型中的 Field 反而获取不到
+	 */
+	protected Class<?> getUsefulClass(Class<?> clazz) {
+		// com.demo.blog.Blog$$EnhancerByCGLIB$$69a17158
+		// return (Class<? extends Model>)((modelClass.getName().indexOf("EnhancerByCGLIB") == -1 ? modelClass : modelClass.getSuperclass()));
+		return (Class<?>)(clazz.getName().indexOf("$$EnhancerBy") == -1 ? clazz : clazz.getSuperclass());
+	}
+	
+	/**
+	 * 设置被注入的对象是否被增强,可使用 @Inject(enhance = YesOrNo.NO) 覆盖此默认值
+	 */
+	public AopProxy setEnhance(boolean enhance) {
+		this.enhance = enhance ? YesOrNo.YES : YesOrNo.NO;
+		return this;
+	}
+	
+	public boolean isEnhance() {
+		return enhance == YesOrNo.YES;
+	}
+	
+	/**
+	 * 设置被注入的对象是否为单例,可使用 @Inject(singleton = YesOrNo.NO) 覆盖此默认值 
+	 */
+	public AopProxy setSingleton(boolean singleton) {
+		this.singleton = singleton ? YesOrNo.YES : YesOrNo.NO;
+		return this;
+	}
+	
+	public boolean isSingleton() {
+		return singleton == YesOrNo.YES;
+	}
+	
+	/**
+	 * 设置注入深度,避免被注入类在具有循环依赖时造成无限循环
+	 */
+	public AopProxy setInjectDepth(int injectDepth) {
+		if (injectDepth <= 0) {
+			throw new IllegalArgumentException("注入层数必须大于 0");
+		}
+		if (injectDepth > MAX_INJECT_DEPTH) {
+			throw new IllegalArgumentException("为保障性能,注入层数不能超过 " + MAX_INJECT_DEPTH);
+		}
+		
+		this.injectDepth = injectDepth;
+		return this;
+	}
+	
+	public int getInjectDepth() {
+		return injectDepth;
+	}
+}
+
+
+/* 未来考虑不再支持对象的 Aop,只支持 Class 的 Aop
+public <T> T get(T targetObject) {
+	try {
+		inject(injectDepth, targetObject.getClass(), targetObject);
+		return targetObject;
+	}
+	catch (Exception e) {
+		throw new RuntimeException(e);
+	}
+}*/
+
+
+
+

+ 24 - 0
src/main/java/com/jfinal/aop/Inject.java

@@ -0,0 +1,24 @@
+package com.jfinal.aop;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Inject is used to inject dependent object
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Inject {
+	
+	Class<?> value() default Void.class;					// 被注入类的类型
+	
+	YesOrNo enhance() default YesOrNo.DEFAULT;			// 是否增强
+	
+	YesOrNo singleton() default YesOrNo.DEFAULT;			// 是否单例
+}
+
+

+ 14 - 0
src/main/java/com/jfinal/aop/YesOrNo.java

@@ -0,0 +1,14 @@
+package com.jfinal.aop;
+
+/**
+ * YesOrNo 用于注解中的常量赋值,参考 Inject 注解的用法
+ */
+public enum YesOrNo {
+	DEFAULT,		// 使用默认配置
+	YES,			// 用 YES 覆盖默认配置
+	NO			// 用 NO 覆盖默认配置
+}
+
+
+
+

+ 1 - 1
src/main/java/com/jfinal/core/ControllerFactory.java

@@ -21,7 +21,7 @@ package com.jfinal.core;
  */
 public class ControllerFactory {
 	
-	public Controller getController(Class<? extends Controller> controllerClass) throws InstantiationException, IllegalAccessException {
+	public Controller getController(Class<? extends Controller> controllerClass) throws ReflectiveOperationException {
 		return controllerClass.newInstance();
 	}
 }

+ 1 - 1
src/main/java/com/jfinal/core/FastControllerFactory.java

@@ -45,7 +45,7 @@ public class FastControllerFactory extends ControllerFactory {
 		}
 	};
 	
-	public Controller getController(Class<? extends Controller> controllerClass) throws InstantiationException, IllegalAccessException {
+	public Controller getController(Class<? extends Controller> controllerClass) throws ReflectiveOperationException {
 		Controller ret = buffers.get().get(controllerClass);
 		if (ret == null) {
 			ret = controllerClass.newInstance();