关于spring,IOC和AOP的解析原理和举例

引用自:https://blog.csdn.net/paincupid/article/details/43152397

IOC:就是DAO接口的实现不再是业务逻辑层调用工厂类去获取,而是通过容器(比如spring)来自动的为我们的业务层设置DAO的实现类。这样整个过程就反过来,以前是我们业务层主动去获取DAO,而现在是DAO主动被设置到业务逻辑层中来了,这也就是反转控制的由来。通过IOC,我们就可以在不修改任何代码的情况下,无缝的实现数据库的换库迁移,当然前提还是必须得写一个实现特定数据库的DAO。我们把DAO普遍到更多的情况下,那么IOC就为我们带来更大的方便性,比如一个接口的多个实现,我们只需要配置一下就ok了,而不需要再一个个的写工厂来来获取了。这就是IOC为我们带来的模块的松耦合和应用的便利性。

  那为什么说IOC很简单呢?说白了其实就是由我们平常的new转成了使用反射来获取类的实例,相信任何人只要会用java的反射机制,那么自己写一个IOC框架也不是不可能的。比如:

  1. public ObjectgetInstance(String className) throws Exception
  2.  

    {

  3.  

      Object obj = Class.forName(className).newInstance();

  4.  

      Method[] methods = obj.getClass().getMethods();

  5.  

      for (Method method : methods) {

  6.  

        if (method.getName().intern() == "setString") {

  7.  

          method.invoke(obj, "hello world!");

  8.  

        }

  9.  

      }

  10.  

    }

  11.  

    ……

  上面的一个方法我们就很简单的使用了反射为指定的类的setString方法来设置一个hello world!字符串。其实可以看到IOC真的很简单,当然了IOC简单并不表示spring的IOC就简单,spring的IOC的功能强大就在于有一系列非常强大的配置文件维护类,它们可以维护spring配置文件中的各个类的关系,这才是spring的IOC真正强大的地方。在spring的Bean定义文件中,不仅可以为定义Bean设置属性,还支持Bean之间的继承、Bean的抽象和不同的获取方式等等功能。

  下次俺再把spring的Bean配置的相关心得和大家一起分享下,如果说的不好,大家可以提意见哦,可千万不要仍臭鸡蛋,嘿嘿~~~~ 

2.关于spring aop

反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) 
好长时间没有用过Spring了. 突然拿起书.我都发现自己对AOP都不熟悉了. 
其实AOP的意思就是面向切面编程. 
OO注重的是我们解决问题的方法(封装成Method),而AOP注重的是许多解决解决问题的方法中的共同点,是对OO思想的一种补充! 
还是拿人家经常举的一个例子讲解一下吧: 
比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们就会在要一些方法前去加上一条日志记录, 
我们写个例子看看我们最简单的解决方案 
我们先写一个接口IHello.java代码如下:

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public interface IHello {

  4.  

  5.  

    void sayHello(String name);

  6.  

    }

1package sinosoft.dj.aop.staticaop; 

3public interface IHello { 
4     
8    void sayHello(String name); 
9} 
10 
里面有个方法,用于输入"Hello" 加传进来的姓名;我们去写个类实现IHello接口

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public class Hello implements IHello {

  4.  

  5.  

    public void sayHello(String name) {

  6.  

    System.out.println("Hello " + name);

  7.  

    }

  8.  

  9.  

    }

现在我们要为这个业务方法加上日志记录的业务,我们在不改变原代码的情况下,我们会去怎么做呢?也许,你会去写一个类去实现IHello接口,并依赖Hello这个类.代码如下:

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public class HelloProxy implements IHello {

  4.  

    private IHello hello;

  5.  

  6.  

    public HelloProxy(IHello hello) {

  7.  

    this.hello = hello;

  8.  

    }

  9.  

  10.  

    public void sayHello(String name) {

  11.  

    Logger.logging(Level.DEBUGE, "sayHello method start.");

  12.  

    hello.sayHello(name);

  13.  

    Logger.logging(Level.INFO, "sayHello method end!");

  14.  

  15.  

    }

  16.  

  17.  

    }

其中.Logger类和Level枚举代码如下: 
Logger.java

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    import java.util.Date;

  4.  

  5.  

    public class Logger{

  6.  

  7.  

    public static void logging(Level level, String context) {

  8.  

    if (level.equals(Level.INFO)) {

  9.  

    System.out.println(new Date().toLocaleString() + " " + context);

  10.  

    }

  11.  

    if (level.equals(Level.DEBUGE)) {

  12.  

    System.err.println(new Date() + " " + context);

  13.  

    }

  14.  

    }

  15.  

  16.  

    }

21Level.java

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public enum Level {

  4.  

    INFO,DEBUGE;

  5.  

    }

那我们去写个测试类看看,代码如下:

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public class Test {

  4.  

    public static void main(String[] args) {

  5.  

    IHello hello = new HelloProxy(new Hello());

  6.  

    hello.sayHello("Doublej");

  7.  

    }

  8.  

    }

运行以上代码我们可以得到下面结果:

Tue Mar 04 20:57:12 CST 2008 sayHello method start. 
Hello Doublej 
2008-3-4 20:57:12 sayHello method end! 
从上面的代码我们可以看出,hello对象是被HelloProxy这个所谓的代理态所创建的.这样,如果我们以后要把日志记录的功能去掉.那我们只要把得到hello对象的代码改成以下:

  1. package sinosoft.dj.aop.staticaop;

  2.  

  3.  

    public class Test {

  4.  

    public static void main(String[] args) {

  5.  

    IHello hello = new Hello();

  6.  

    hello.sayHello("Doublej");

  7.  

    }

  8.  

    }

上面代码,可以说是AOP最简单的实现! 
但是我们会发现一个问题,如果我们像Hello这样的类很多,那么,我们是不是要去写很多个HelloProxy这样的类呢.没错,是的.其实也是一种很麻烦的事.在jdk1.3以后.jdk跟我们提供了一个API   java.lang.reflect.InvocationHandler的类. 这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.让我们把以上的代码改一下来看看效果.
同样,我们写一个IHello的接口和一个Hello的实现类.在接口中.我们定义两个方法;代码如下 :

  1. IHello.java

  2.  

    package sinosoft.dj.aop.proxyaop;

  3.  

  4.  

    public interface IHello {

  5.  

  6.  

    void sayHello(String name);

  7.  

  8.  

    void sayGoogBye(String name);

  9.  

    }

  10.  

  11.  

  12.  

    Hello.java

  13.  

  14.  

    package sinosoft.dj.aop.proxyaop;

  15.  

  16.  

    public class Hello implements IHello {

  17.  

  18.  

    public void sayHello(String name) {

  19.  

    System.out.println("Hello " + name);

  20.  

    }

  21.  

    public void sayGoogBye(String name) {

  22.  

    System.out.println(name+" GoodBye!");

  23.  

    }

  24.  

    }

我们一样的去写一个代理类.只不过.让这个类去实现java.lang.reflect.InvocationHandler接口,代码如下:

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    import java.lang.reflect.InvocationHandler;

  4.  

    import java.lang.reflect.Method;

  5.  

    import java.lang.reflect.Proxy;

  6.  

  7.  

    public class DynaProxyHello implements InvocationHandler {

  8.  

  9.  

  10.  

    private Object delegate;

  11.  

  12.  

  13.  

    public Object bind(Object delegate) {

  14.  

    this.delegate = delegate;

  15.  

    return Proxy.newProxyInstance(

  16.  

    this.delegate.getClass().getClassLoader(), this.delegate

  17.  

    .getClass().getInterfaces(), this);

  18.  

    }

  19.  

  20.  

    public Object invoke(Object proxy, Method method, Object[] args)

  21.  

    throws Throwable {

  22.  

    Object result = null;

  23.  

    try {

  24.  

    //执行原来的方法之前记录日志

  25.  

    Logger.logging(Level.DEBUGE, method.getName() + " Method end .");

  26.  

  27.  

    //JVM通过这条语句执行原来的方法(反射机制)

  28.  

    result = method.invoke(this.delegate, args);

  29.  

    //执行原来的方法之后记录日志

  30.  

    Logger.logging(Level.INFO, method.getName() + " Method Start!");

  31.  

    } catch (Exception e) {

  32.  

    e.printStackTrace();

  33.  

    }

  34.  

    //返回方法返回值给调用者

  35.  

    return result;

  36.  

    }

  37.  

  38.  

    }

上面类中出现的Logger类和Level枚举还是和上一上例子的实现是一样的.这里就不贴出代码了.

让我们写一个Test类去测试一下.代码如下: 
Test.java

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    public class Test {

  4.  

    public static void main(String[] args) {

  5.  

    IHello hello = (IHello)new DynaProxyHello().bind(new Hello());

  6.  

    hello.sayGoogBye("Double J");

  7.  

    hello.sayHello("Double J");

  8.  

  9.  

    }

  10.  

    }

运行输出的结果如下: 
Tue Mar 04 21:24:03 CST 2008 sayGoogBye Method end . 
Double J GoodBye! 
2008-3-4 21:24:03 sayGoogBye Method Start! 
Tue Mar 04 21:24:03 CST 2008 sayHello Method end . 
Hello Double J 
2008-3-4 21:24:03 sayHello Method Start! 
由于线程的关系,第二个方法的开始出现在第一个方法的结束之前.这不是我们所关注的! 
从上面的例子我们看出.只要你是采用面向接口编程,那么,你的任何对象的方法执行之前要加上记录日志的操作都是可以的.他(DynaPoxyHello)自动去代理执行被代理对象(Hello)中的每一个方法,一个java.lang.reflect.InvocationHandler接口就把我们的代理对象和被代理对象解藕了.但是,我们又发现还有一个问题,这个DynaPoxyHello对象只能跟我们去在方法前后加上日志记录的操作.我们能不能把DynaPoxyHello对象和日志操作对象(Logger)解藕呢?
结果是肯定的.让我们来分析一下我们的需求. 
我们要在被代理对象的方法前面或者后面去加上日志操作代码(或者是其它操作的代码), 
那么,我们可以抽象出一个接口,这个接口里就只有两个方法,一个是在被代理对象要执行方法之前执行的方法,我们取名为start,第二个方法就是在被代理对象执行方法之后执行的方法,我们取名为end .接口定义如下 :

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    import java.lang.reflect.Method;

  4.  

  5.  

    public interface IOperation {

  6.  

  7.  

    void start(Method method);

  8.  

  9.  

    void end(Method method);

  10.  

    }

我们去写一个实现上面接口的类.我们把作他真正的操作者,如下面是日志操作者的一个类: 
LoggerOperation.java

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    import java.lang.reflect.Method;

  4.  

  5.  

    public class LoggerOperation implements IOperation {

  6.  

  7.  

    public void end(Method method) {

  8.  

    Logger.logging(Level.DEBUGE, method.getName() + " Method end .");

  9.  

    }

  10.  

  11.  

    public void start(Method method) {

  12.  

    Logger.logging(Level.INFO, method.getName() + " Method Start!");

  13.  

    }

  14.  

  15.  

    }

然后我们要改一下代理对象DynaProxyHello中的代码.如下:

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    import java.lang.reflect.InvocationHandler;

  4.  

    import java.lang.reflect.Method;

  5.  

    import java.lang.reflect.Proxy;

  6.  

  7.  

    public class DynaProxyHello implements InvocationHandler {

  8.  

  9.  

    private Object proxy;

  10.  

  11.  

    private Object delegate;

  12.  

  13.  

  14.  

    public Object bind(Object delegate,Object proxy) {

  15.  

  16.  

    this.proxy = proxy;

  17.  

    this.delegate = delegate;

  18.  

    return Proxy.newProxyInstance(

  19.  

    this.delegate.getClass().getClassLoader(), this.delegate

  20.  

    .getClass().getInterfaces(), this);

  21.  

    }

  22.  

  23.  

    public Object invoke(Object proxy, Method method, Object[] args)

  24.  

    throws Throwable {

  25.  

    Object result = null;

  26.  

    try {

  27.  

    //反射得到操作者的实例

  28.  

    Class clazz = this.proxy.getClass();

  29.  

    //反射得到操作者的Start方法

  30.  

    Method start = clazz.getDeclaredMethod("start",

  31.  

    new Class[] { Method.class });

  32.  

    //反射执行start方法

  33.  

    start.invoke(this.proxy, new Object[] { method });

  34.  

    //执行要处理对象的原本方法

  35.  

    result = method.invoke(this.delegate, args);

  36.  

    // 反射得到操作者的end方法

  37.  

    Method end = clazz.getDeclaredMethod("end",

  38.  

    new Class[] { Method.class });

  39.  

    // 反射执行end方法

  40.  

    end.invoke(this.proxy, new Object[] { method });

  41.  

  42.  

    } catch (Exception e) {

  43.  

    e.printStackTrace();

  44.  

    }

  45.  

    return result;

  46.  

    }

  47.  

  48.  

    }

然后我们把Test.java中的代码改一下.测试一下:

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    public class Test {

  4.  

    public static void main(String[] args) {

  5.  

    IHello hello = (IHello)new DynaProxyHello().bind(new Hello(),new LoggerOperation());

  6.  

    hello.sayGoogBye("Double J");

  7.  

    hello.sayHello("Double J");

  8.  

  9.  

    }

  10.  

    }

结果还是一样的吧.

如果你想在每个方法之前加上日志记录,而不在方法后加上日志记录.你就把LoggerOperation类改成如下:

  1. package sinosoft.dj.aop.proxyaop;

  2.  

  3.  

    import java.lang.reflect.Method;

  4.  

  5.  

    public class LoggerOperation implements IOperation {

  6.  

  7.  

    public void end(Method method) {

  8.  

    //Logger.logging(Level.DEBUGE, method.getName() + " Method end .");

  9.  

    }

  10.  

  11.  

    public void start(Method method) {

  12.  

    Logger.logging(Level.INFO, method.getName() + " Method Start!");

  13.  

    }

  14.  

  15.  

    }

运行一下.你就会发现,每个方法之后没有记录日志了. 这样,我们就把代理者和操作者解藕了!

下面留一个问题给大家,如果我们不想让所有方法都被日志记录,我们应该怎么去解藕呢.?

我的想法是在代理对象的public Object invoke(Object proxy, Method method, Object[] args)方法里面加上个if(),对传进来的method的名字进行判断,判断的条件存在XML里面.这样我们就可以配置文件时行解藕了.如果有兴趣的朋友可以把操作者,被代理者,都通过配置文件进行配置 ,那么就可以写一个简单的SpringAOP框架了.

原文地址:https://www.cnblogs.com/2019lgg/p/11188743.html

时间: 2024-08-25 02:19:04

关于spring,IOC和AOP的解析原理和举例的相关文章

Spring IOC及AOP学习总结

一.Spring IOC体系学习总结: Spring中有两个容器体系,一类是BeanFactory.另一类是ApplicationContext.BeanFactory提供了基础的容器功能.ApplicationContext则是基于BeanFactory建立的一套更加丰富的容器体系,基于ApplicationContext构建了Spring AOP体系(基于AOP体系又构建了声明式事务模型),I18n的支持,基于观察者模式的事件模型,多渠道的Bean资源的载入(比如从文件系统,从interne

Spring IOC 和 AOP

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. 1.控制反转(IOC)/依赖注入(DI): 在传统的程序设计中,当调用者须要被调用者的协助时,通常由调用者来创建被调用者的实例. 但在spring里创建被调用者的工作不再由调用者来完毕.因此控制反转(IoC),为什么称为反转呢?反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,假设要在A里面使用C,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所须要的外部资源C.这样的

spring - ioc和aop

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

IOC和AOP的基础原理

IoC(Inversion of Control)就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控.这也就是所谓“控制反转”的概念所在.控制权由应用代码中转到了外部容器,控制权的转移是所谓反转.IoC还有另外一个名字——“依赖注入(Dependency Injection)”.从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象地说,即由容器动态地将某种依赖关系注入到组件之中. IoC是近年来兴起的一种思想,不仅仅是编程思想.主要是协调各组件间相互的依赖关系,

spring ioc和aop理解

spring IOC 1.目的:就是解决程序间的依赖关系 2.原理:通过反射原理将我们控制层中的 dao层. service层类以工厂模式在static代码块中实现加载后存放入map中 , 并实现单列 . 原文地址:https://www.cnblogs.com/cwone/p/11939192.html

面试之Spring框架IOC和AOP的实现原理

IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中转到了外部容器,控制权的转移是所谓反转. 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系:IoC还有另外一个名字--"依赖注入(Dependency Injection)".从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某

Spring框架IOC和AOP的实现原理

IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中转到了外部容器,控制权的转移是所谓反转. 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系:IoC还有另外一个名字--"依赖注入(Dependency Injection)".从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某

Spring IOC, DI, AOP 原理和实现

介绍的比较详细(概念): http://blog.csdn.net/mdcmy/article/details/8542277 http://my.oschina.net/u/1012289/blog/136648 系统的学习: http://openhome.cc/Gossip/SpringGossip/

Spring+IOC(DI)+AOP概念及优缺点

Spring pring是一个轻量级的DI和AOP容器框架. 说它轻量级有一大部分原因是相对与EJB的(虽然本人从没有接触过EJB的应用),重要的是,Spring是非侵入式的,基于spring开发的应用一般不依赖于spring的类. 容器:Spring是个容器,因为它包含并且管理应用对象的生命周期和配置.如对象的创建.销毁.回调等. 框架:Spring作为一个框架,提供了一些基础功能,(如事务管理,持久层集成等),使开发人员更专注于开发应用逻辑. Spring的优点1.降低了组件之间的耦合性 ,