Spring从菜鸟到高手(一)实现AOP的基本原理

Spring为Java大地带来了一阵春风,它作为一个优秀的轻量级企业应用开发框架,能够大大简化企业应用开发的复杂性。Spring以反向控制和AOP这两样先进的设计理念为基础,统一了应用对象的查找、配置和生命周期的管理,分离了业务与基础服务中的不同关注点

Spring AOP实现原理

Spring为Java大地带来了一阵春风,它作为一个优秀的轻量级企业应用开发框架,能够大大简化企业应用开发的复杂性。

Spring以反向控制和AOP这两样先进的设计理念为基础,统一了应用对象的查找、配置和生命周期的管理,分离了业务与基础服务中的不同关注点,开发人员可以基于简单Java对象轻松的实现与EJB同样强大的功能。

AOP经常被定义为一种编程技术,用来在系统中提升业务的分离,系统有很多组件组成,每一组件负责一部分功能。然而,这些组件也经常带有一些除了核心功能之外的附带功能。系统服务如日志、事务管理和安全经常融入到一些其他功能模块中。这些系统服务通常叫做交叉业务,这是因为,它们总是分布在系统的很多组件中,通过将这些业务分布在多个组件中,你给你的代码引入了双重复杂性。

---摘自《Spring in Action》

今天我给大家介绍一下Spring是如何实现AOP技术的,这里需要一些反射和代理的知识,大家可以看我以前的文章,里面有关于反射代理的讲解和代码演示,我们可以通过AOP技术在目标对象不知情的情况之下做一些参数的验证或者一些日志记录,而目标对象并不用操心我们对他作了什么(其实他根本就不知道我们做了什么)因为所有的一切我们是在目标对象的代理类中实现的,下面我给大家讲解一下我所理解的AOP技术。

讲解AOP时,我还是使用我关于代理那篇文章中的例子:

首先需要一个接口

interface Foo {
    public String printMessage(String message);
}

一个实现这个接口的类

public class FooClass implements Foo {
    public String printMessage(String message){
        return "This is Object FooClass~!" + message;
    }
}

一个实现了InvocationHandler接口的类(这个类用于实现面向切面)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
public class MyInvocationHandler implements InvocationHandler {
    private Object fooClass;
    
    public MyInvocationHandler(Object fooClass) {
        this.fooClass = fooClass;
    }
    
    public Object invoke(Object arg0, Method arg1, Object[] arg2)throws Throwable{
        BasicConfigurator.configure();
        Log log = LogFactory.getLog(MyInvocationHandler.class);
        log.info("This is " + MyInvocationHandler.class.getName() + "You want invoke "+ arg1.getName());
        return arg1.invoke(fooClass,arg2);
    }
}

一个实现了FactoryBean接口的类(FactoryBean接口在Spring中用于得到一个ProxyObject对象)

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean {
    private String target = null;
    private String interf = null;
    
    public Object getObject() throws Exception {
        /**
         * 在这个方法中我们通过java的代理技术得到了一个代理类,
         * 所有的参数都是通过XML文件传递给BeanFactory的所以我
         * 们需要一个BeanFactory的对象和一个启动运行类
         */
        Class[] interClass = new Class[]{Class.forName(interf)};
        Object objTarget = Class.forName(target).newInstance();
        Object objProxy =Proxy.newProxyInstance(Foo.class.getClassLoader(),interClass,new
        MyInvocationHandler(objTarget));
        return objProxy;
    }

    public Class getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }

    public String getInterf() {
        return interf;
    }

    public void setInterf(String interf) {
        this.interf = interf;
    }
}

一个启动运行类,其中有BeanFactory对象的实例

import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
//使用了log4j.properties文件,如果不实用这个文件可以使用这个包
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
//如果要使用绝对路径读取*.XML文件可以使用这个包
public class MainClass {
    public static void main(String[] args) throws Exception {
        //BasicConfigurator.configure();
        
        Log log = LogFactory.getLog(MainClass.class);//实例一个Log对象
        BeanFactory factory = new XmlBeanFactory(new ClassPathResource("/applicationContext.xml"));
        //通过XmlBeanFactory来读取applicationContext.xml文件
        
        Foo foo =(Foo)factory.getBean("bean");
        // 此时Spring会自动调用factory.getObject方法,返回一个对象
        // 此时的factory.getBean("bean")是如何的一个Foo对象的呢?
        // 他又是如何知道应该调用MyFactoryBean.getObject()
        // 的方法呢?我给大家简单讲解一下BeanFactory类的getBean
        // 方法的工作原理,首先我们在实例化BeanFactory的对象的时候
        // 会读取一个XML文件此时XML文件中的所有内容都将存到factory
        // 对象的内部,每当我们调用factory.getBean("xxx")时
        // 它会在自身内部寻找<bean>标签中id属性为"xxx"的bean将其注入并且实例化。
        
        log.info(foo.printMessage("Hello I'm Tony"));//调用这个对象的方法
    }
}

applicationContext.xml文件的全部内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "[url]https://www.springframework.org/dtd/spring-beans.dtd[/url]">
<beans>
    <bean id="bean" class="MyFactoryBean">
        <property name="target">
        <value>FooClass</value>
        </property>
        <property name="interf">
        <value>Foo</value>
        </property>
    </bean>
</beans>

log4j.properties文件的全部内容

log4j.rootLogger=info,sysout
log4j.appender.sysout=org.apache.log4j.ConsoleAppender
log4j.appender.sysout.layout=org.apache.log4j.SimpleLayout

applicationContext.xml和log4j.properties放在classpath路径下,ClassPathResource和LogFactory会自动找到了

我们一定不要当三等公民:等下班、等薪水、等退休。
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号