IOC和AOP的简单实现

一直使用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。

时间: 2024-08-29 15:37:43

IOC和AOP的简单实现的相关文章

对Spring中的IOC与AOP简单理解(简单的理解,通俗易懂)

IOC与AOP是Spring中的核心:IOC是控制反转,AOP是面向对象编程,IOC采用了工厂设计模式,AOP采用了代理设计模式. 一.IOC IOC是控制反转,而控制反转是一种思想,而DI是依赖注入,是IOC的实现,DI有构造注入.属性注入(设值注入)(基于注解的方式或者基于XML的方式).在项目程序中,频繁的去手动创建对象,new对象使得代码间耦合度太大,而Spring提供了容器,通俗的讲:你无需知道对象的创建过程,只需从其中拿到结果就可以了:把对象的创建以及各个对象间的关系还有对象的销毁交

Spring入门导读——IoC和AOP

和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(Inversion of Control)控制反转 什么是控制反转呢?可以这么通俗的来解释,我们通常写代码当一个类会关联另一个类是会直接在这个类里new,例如: 1 package day_30_spring; 2 3 /** 4 * @author 余林丰 5 * 6 * 2016年10月30日 7

Java深度历险(四) 深入浅出-----IOC AND AOP

IOC就是Inversion of Control,控制反转.在Java开发中,IoC意味着将你设计好的类交给系统(容器)来控制实现,而不是在你的类内部控制.这称为控制反转. 本人理解:就是把原本你自己制造,使用的对象,现在交由别人制造,而通过构造函数(容器来管理),setter方法或方法(这里指使用这个对象的方法)参数的方式传给自己,由自己使用. 实例说明形象理解IOC 要设计一个Girl和一个Boy类,其中Girl有recognize方法,即Girl想要recognize一个Boy.那么,我

spring的IOC和AOP

spring的核心就是IOC和AOP. IOC(控制反转)和DI(依赖注入)是同一个概念.具体的讲:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例.但在spring中 创建被调用者的工作不再由调用者来完成,因此称为控制反转.创建被调用者的工作由spring来完成,然后注入调用者因此也称为依赖注入.所谓依赖,从程序的角度看,就是比如A要调用B的方法,那么A就依赖于B,反正A要用到B,则A依赖于B.举个生活中的例子:通常情况下,假如你有一天在家里口渴了

maven-tomcat7;IOC;AOP;数据库远程连接

[说明]真的是好烦下载插件啊,maven-tomcat7 插件试了好多次都不行,下载不成:部署不成:好不容易从github中得到的springmvc项目也是运行不起来,中间又是查了许多东西,绕着绕着都不知到到那里了,啊啊啊 [说明]明天还有我们郑州这边的分享,按说该到我了,还得好好准备,, 一:今日完成 1)spring建了一个简单的javaweb项目,大概实验了IOC和AOP的功能 不过到后面springmvc运行的时候,因为修改了server.xml文件,出现了好多问题,tomcat启动不了

spring的IOC和AOP详细讲解

1.解释spring的ioc? 几种注入依赖的方式?spring的优点? IOC你就认为他是一个生产和管理bean的容器就行了,原来需要在调用类中new的东西,现在都是有这个IOC容器进行产生,同时,要是产生的是单例的bean,他还可以给管理bean的生命周期! spring的IOC有三种注入方式 : 第一是根据属性注入 也叫set方法注入: 第二种是根据构造方法进行注入: 第三种是根据注解进行注入,这种方式我认为比较好,方便,要是bean多的话,使用前两种方式会使得配置文件过于臃肿. Spri

spring - ioc和aop

1.程序中为什么会用到spring的ioc和aop 2.什么是IOC,AOP,以及使用它们的好处,即详细回答了第一个问题 3.原理 关于1: a:我们平常使用对象的时候,一般都是直接使用关键字类new一个对象,那这样有什么坏处呢?其实很显然的,使用new那么就表示当前模块已经不知不觉的和 new的对象耦合了,而我们通常都是更高层次的抽象模块调用底层的实现模块,这样也就产生了模块依赖于具体的实现,这样与我们JAVA中提倡的面向接口面向抽象编程是相冲突的,而且这样做也带来系统的模块架构问题.很简单的

IOC和AOP的基本概念

一.什么是IOC IoC就是Inversion of Control,控制反转.在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制.这称为控制反转. 下面我们以几个例子来说明什么是IoC 假设我们要设计一个Girl和一个Boy类,其中Girl有kiss方法,即Girl想要Kiss一个Boy.那么,我们的问题是,Girl如何能够认识这个Boy? 在我们中国,常见的MM与GG的认识方式有以下几种 1 青梅竹马: 2 亲友介绍: 3 父母包办 那么哪一种才是最好呢? 青

深入理解IOC模式及Unity简单应用

研究了下,有几篇博客确实已经说得很清楚了 1.IoC模式:http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075.html  这篇博客是通过一个播放器的例子来说明什么是依赖,依赖倒置,控制反转(IOC),最后实现依赖注入.通过Unity实现IOC容器.不错的一个例子 2.深入理解DIP.IoC.DI以及IoC容器 这个算是最通俗易懂的,手动实现了IOC容器  由浅入深 3.理解依赖注入(IOC)和学习Unity 这个也不错,特别最后介绍的挺