以注解方式模拟Spring的IoC,AOP

来源:互联网 发布:android 相机源码 编辑:程序博客网 时间:2024/06/15 20:32

目录结构:


@Component注解代码:

package glut.annotation;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 value() default "";}

@Resource代码:

package glut.annotation;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Resource {String value();// 默认要给出需要注入的实例名}


Ioc实现代码:

package glut.spring;import glut.annotation.Component;import glut.annotation.Resource;import java.io.File;import java.lang.reflect.Field;import java.util.Collection;import java.util.HashMap;import java.util.Map;public class BeanFactory {/** * pkg:package to scan; */private String pkg;/** * 将Component注解的value返回值作为key,对应的类作为value,存放在instanceMap中 */private Map<String, Object> instanceMap = new HashMap<>();/** * 如果使用无参构造器,之后请记得使用setPkg方法 */public BeanFactory() {// TODO Auto-generated constructor stub}/** * 调用该构造器会回调ioc *  * @param pkg */public BeanFactory(String pkg) {this.pkg = pkg;IoC();}private void IoC() {// 将包形式转换为文件路径形式String pkgPath = pkg.replaceAll("\\.", "/");// 获取当前project的绝对路径String projectPath = BeanFactory.class.getResource("/").toString();// 对获取的路径进行处理,去掉开头的file:/projectPath = projectPath.substring(projectPath.indexOf("/") + 1);// 获取指定路径下的所有文件// 遍历所有的文件和文件夹recursion(new File(projectPath + pkgPath));findResource();}// 将instanceMap里所有的实例的filed找出,看看是否存在@Resource,如果存在就将它实例化private void findResource() {// TODO Auto-generated method stub// 获取指定路径pkg下存在@Component的所有对象实例Collection<Object> values = instanceMap.values();for (Object obj : values) {try {initResource(obj);} catch (IllegalArgumentException | IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}/** * 初始化带有@Resource的field *  * @param obj *            field的拥有者 * @throws IllegalArgumentException * @throws IllegalAccessException */private void initResource(Object obj) throws IllegalArgumentException,IllegalAccessException {// TODO Auto-generated method stubClass<? extends Object> clz = obj.getClass();Field[] fields = clz.getDeclaredFields();for (Field f : fields) {Class<Resource> res = Resource.class;if (f.isAnnotationPresent(res)) {Resource r = f.getAnnotation(res);String resName = r.value();Object o = instanceMap.get(resName);f.setAccessible(true);f.set(obj, o);}}}/** * 递归寻找指定路径下的所有类文件 *  * @param file */private void recursion(File file) {File[] files = file.listFiles();for (File f : files) {if (f.isFile()) {fillMap(f);} else {recursion(f);}}}/** * 对找到类文件进行处理,将该类文件头上的注解解析,将对应信息存放到map中 *  * @param f */private void fillMap(File f) {// 类的绝对路径String absolutePath = f.getAbsolutePath();// 包路径String pkgPath = absolutePath.replaceAll("\\\\", ".");// 获取类路径,并去掉文件格式String objPath = pkgPath.substring(pkgPath.indexOf(pkg),pkgPath.length() - 6);try {// 通过类路径创建指定的类Class<?> clz = Class.forName(objPath);Class<Component> annoClz = Component.class;Class<Resource> res = Resource.class;if (clz.isAnnotationPresent(annoClz)) {Component c = clz.getAnnotation(annoClz);Object instance = clz.newInstance();String instanceName = "";String annoValue = c.value();// 如果使用的是默认值,则以类名为key存入mapif ("".equals(annoValue)) {instanceName = instance.getClass().getSimpleName();// 将类名第一个字母改成小写instanceName = (instanceName.charAt(0) + "").toLowerCase()+ instanceName.substring(1);} else {instanceName = annoValue;}// 存放到map中,如果返回值不为空,则表明已存在同名实例.if (instanceMap.put(instanceName, instance) != null) {throw new Exception("存在同名实例");}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}public Map<String, Object> getInstances() {return instanceMap;}/** * 根据实例名获取实例 *  * @param instanceName *            实例名 * @return 实例 */public <T> T getInstance(String instanceName) {return (T) instanceMap.get(instanceName);}public String getPkg() {return pkg;}/** * 调用set方法会回调IoC *  * @param pkg */public void setPkg(String pkg) {this.pkg = pkg;IoC();}}


AOP实现代码:

package glut.spring;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class DynamicProxy implements InvocationHandler {private Object target;public DynamicProxy() {// TODO Auto-generated constructor stub}public DynamicProxy(Object target) {super();this.target = target;}public static <T> T bind(Object obj) {Class<? extends Object> clz = obj.getClass();return (T) Proxy.newProxyInstance(clz.getClassLoader(),clz.getInterfaces(), new DynamicProxy(obj));}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubbefore(proxy, method, args);Object invoke = method.invoke(target, args);after(proxy, method, args);return invoke;}private void before(Object proxy, Method method, Object[] args) {// TODO Auto-generated method stubSystem.out.println("Before:" + " Class Name:"+ target.getClass().getSimpleName() + "     method name:"+ method.getName());}private void after(Object proxy, Method method, Object[] args) {// TODO Auto-generated method stubSystem.out.println("After :" + " Class Name:"+ target.getClass().getSimpleName() + "     method name:"+ method.getName());}public Object getTarget() {return target;}public void setTarget(Object target) {this.target = target;}}


studentDAOImp和teacherDAOImp都带有@Component注解,比较简单.这里只给出studentServiceImp的代码:

package glut.service;import glut.annotation.Component;import glut.annotation.Resource;import glut.dao.IStudentDAO;import glut.dao.ITeacherDAO;@Componentpublic class StudentServiceImp implements IStudentService {@Resource("studentDAOImp")private IStudentDAO sd;@Resource("teacherDAOImp")private ITeacherDAO td;@Overridepublic void save() {// TODO Auto-generated method stub// 通过该servvice调用sd,td两个dao.sd.save();td.save();}}


MyTest测试代码:

package glut.test;import glut.service.IStudentService;import glut.spring.BeanFactory;import glut.spring.DynamicProxy;import org.junit.Test;public class MyTest {@Testpublic void test() {// pkgToScan:要扫描的包路径,多个同前缀的包会递归处理String pkgToScan = "glut";BeanFactory bf = new BeanFactory(pkgToScan);IStudentService iss = bf.getInstance("studentServiceImp");// AOP绑定iss = DynamicProxy.bind(iss);iss.save();}}

输出结果:

Before: Class Name:StudentServiceImp     method name:save
StudentDAOImp save
TeacherDAOImp save
After : Class Name:StudentServiceImp     method name:save



写了这个例子,对Spring的理解又更深了一步.


源码下载:

CSDN:http://download.csdn.net/detail/lc0817/9100991

SVN repository:http://code.taobao.org/svn/Spring_Simulation/

0 0
原创粉丝点击