码迷,mamicode.com
首页 > 其他好文 > 详细

IOC和AOP的简单实现

时间:2015-01-28 14:18:17      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:

一直使用spring,说起来就是IOC和AOP,看过不少原理的书,但是spring的代码太多,梳理起来很困难,于是想自己实现一下,昨天下午写出代码来,分享一下。

目标:

1、使用annotation编程进行分层,有service层和dao层(mapper层)。

2、设置容器,将所有的实例注入到容器里,类似spring的applicationContext。

3、dao层使用接口,没有实现类,类似于ibitas的使用方式。

4、读取本地文件内容。

 

根据目标大概思考并实践了以下几点:

1、动态代理选用cglib实现,首先这是spring的实现方式,其次亲测使用jdk的反射包无法实现对接口的动态代理,无法满足上述目标3。

2、容器使用单例模式创建,保证所有的bean只有一个。

 

代码如下:

首先是自定义的Annotation,为了和spring的加以区别,我都加上了Fx前缀。

第一个是FxMapper,类似spring的@Repository,也就是Dao层应该加的Annotation

package com.smikevon.proxy.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by fengxiao on 15-1-27.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FxMapper {
    String value();
}

第二个是FxService对应于spring的service层,类似spring的@Service。

package com.smikevon.proxy.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by fengxiao on 15-1-27.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FxService {
    String value();
}

第三个FxResource对应spring里的@Resource,也就是类内饮用的注释

package com.smikevon.proxy.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by fengxiao on 15-1-27.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FxResource {
    String value();
}

 

Annotation类全部贴完,下面贴出各层的一个示例类。

按上面顺序,第一个mapper类

package com.smikevon.proxy.dynamic;
import com.smikevon.proxy.annotations.FxMapper; /** * Created by fengxiao on 15-1-27. */ @FxMapper("fileMapper") public interface FileMapper { public String read(String fileDir); public void append(String fileDir , String message); }

第二个service类

package com.smikevon.proxy.dynamic;

import com.smikevon.proxy.annotations.FxResource;
import com.smikevon.proxy.annotations.FxService;

/**
 * Created by fengxiao on 15-1-27.
 */
@FxService("fileService")
public class FileService {
    String file = "rFile.txt";
    
    @FxResource(value="fileMapper")
    public FileMapper fileMapper;

    public void read(){
        System.out.println("hello world");
        String txt = fileMapper.read(file);
        System.out.println("message:"+txt);
    }
}

 

示例类已经贴完,下面贴出容器类。容器类通过使用一个hashmap来实现容器,这里没有考虑线程安全的问题,只是为了示例。初始化使用静态内部类来实现单例模式。

package com.smikevon.proxy.dynamic;

import com.smikevon.proxy.Processors.FileMapperProcessor;
import com.smikevon.proxy.Processors.FileServiceProcessor;
import com.smikevon.proxy.annotations.FxMapper;
import com.smikevon.proxy.annotations.FxService;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by fengxiao on 15-1-27.
 */
public class FxApplicationContext {
    
    private static final String JAVA_SOURCE_DIR = "src/main/java";
    private static final String JAVA_PACKAGE_DIR = "com/smikevon/proxy/dynamic";
    private static final String JAVA_PACKAGE_PATH = "com.smikevon.proxy.dynamic";
    
    private Map<String,Object> context = new HashMap<String,Object>();
    
    private FxApplicationContext(){}

    /**
     * 容器初始化
     */
    public FxApplicationContext init(){
        try {
            File file1 = new File(JAVA_SOURCE_DIR+File.separator+JAVA_PACKAGE_DIR);
            File[] files = file1.listFiles();
            for(File file : files){
                if(file.getName().endsWith("java")){
                    String name = file.getName().substring(0,file.getName().indexOf("."));
                    Class<?> clazz = Class.forName(JAVA_PACKAGE_PATH+"."+name);
                    if(clazz.getAnnotation(FxMapper.class)!=null){
                        String key = clazz.getAnnotation(FxMapper.class).value();
                        //实例化mapper的处理类
                        FileMapperProcessor processor = new FileMapperProcessor();
                        if(context.get(key) == null){
                            context.put(key,processor.bind(clazz));
                        }
                    }
                    if(clazz.getAnnotation(FxService.class)!=null){
                        String key = clazz.getAnnotation(FxService.class).value();
                        //实例化service的处理类
                        FileServiceProcessor processor = new FileServiceProcessor();
                        if(context.get(key) == null){
                            context.put(key,processor.bind(clazz));
                        }
                    }
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return this;

    }

    public Object getBean(String beanId){
        Iterator<Map.Entry<String, Object>> iterator = context.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<String, Object> entry = iterator.next();
            String key = entry.getKey();
            if(key.equals(beanId)){
                return entry.getValue();
            }
        }
        return null;
    }

    /**
     * 静态内部类方式实现单例
     */
    private static class FxApplicationContextHolder{
        public static FxApplicationContext instance = new FxApplicationContext();
    }
    
    public static FxApplicationContext getInstance(){
        return FxApplicationContextHolder.instance;
    }
    
}

 

动态代理引用了cglib包,在项目里要加上如下引用:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

代理类如下:

先是对有@FxMapper标记的类的动态代理方法

package com.smikevon.proxy.Processors;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Method;

/**
 * Created by fengxiao on 15-1-27.
 */
public class FileMapperProcessor implements MethodInterceptor{

    public Object bind(Class clazz) {
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(this);
        enhancer.setSuperclass(clazz);
        Object obj = enhancer.create();
        return obj;
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        StringBuilder sb = new StringBuilder();
        if(method.getName().toLowerCase().startsWith("read")){
            if (objects.length > 0) {
                String fileDir = (String) objects[0];
                File file = new File(fileDir);
                BufferedReader br = new BufferedReader(new FileReader(file));
                
                String line = null;
                while((line = br.readLine())!=null){
                    sb.append(line);
                }
            }
        }
        return sb.toString();
    }
}

其次是对有@FxService标记的类的动态代理方法

package com.smikevon.proxy.Processors;

import com.smikevon.proxy.annotations.FxResource;
import com.smikevon.proxy.dynamic.FxApplicationContext;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by fengxiao on 15-1-27.
 */
public class FileServiceProcessor implements MethodInterceptor{

    private Object target;
    
    public Object bind(Class clazz) {
        try {
            target = clazz.newInstance();
            
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            Object obj = enhancer.create();
    
            //将mapper的实例bean赋值给对应的引用
            Field[] fields = clazz.getDeclaredFields();
            for(Field field : fields){
                if (field.getAnnotation(FxResource.class)!=null){
                    String value = field.getAnnotation(FxResource.class).value();
                    Object object = FxApplicationContext.getInstance().getBean(value);
                    //看到没下面这行代码和注释掉的代码效果是一样的,反射的强大之处
                    field.set(target,object);
                    //((FileService)target).fileMapper = (FileMapper)object;
                }
            }
            return obj;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        method.invoke(target,objects);
        return null;
    }
}

其实,@FxService和@FxMapper可以合并成一个Annotation,对应的动态代理类也可以合并为一个(类似Spring的@Component ),但是那样的话,每个类的处理逻辑就会比较复杂,不易理解。

下面是测试方法类:

package com.smikevon.proxy.dynamic;

import java.lang.reflect.InvocationTargetException;

/**
 * Created by fengxiao on 15-1-27.
 */
public class FileDemo {
    
    public static void main(String[] args) throws InvocationTargetException {
        FxApplicationContext fxApplicationContext = FxApplicationContext.getInstance().init();
        FileService fileService = (FileService)fxApplicationContext.getBean("fileService");
        fileService.read();
    }
    
}

我的文件内容(文件名fFile.txt,位置就在项目根目录):

hello , my name is Mr Read!

I love reading books!

输出结果:

hello world
message:hello , my name is Mr Read!I love reading books!

 

看下有没有很熟悉,和spring使用bean的方式是不是很一致? 原理原来没有什么神秘的,就是这么简单。

 

这里那里用到了IOC?

容器方式初始化bean,将bean的生命周期交付给容器(hashmap),而不是调用者,示例里容器的生命周期比较简单,即调用init()方法后开始,程序执行完成结束。

 

这里那里用到了AOP?

通过动态代理读取接口参数,获取相应文件内容,这就是aop。

 

IOC和AOP的简单实现

标签:

原文地址:http://www.cnblogs.com/seanvon/p/4255505.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!