Spring专题

使用Spring实现AOP源码

使用Spring实现AOP源码下载

在面向对象系统中,我们经常需要一些任务活动,如记录,交易的安全性,缓存等,这些活动是必要的,但不是业务逻辑的一部分,被称为"横切关注点"。

(横切关注==跨整个系统的常用功能)

   从业务逻辑中分离横切关注点,为写出一个精心设计的解耦系统迈出了一大步。让我们关注思考如何处理横切关注点的分离。

   继承Inheritance

   继承的是那些通用功能,继承需要我们设计一个基类,如果我们要重用到多个地方可能需要修改这个基类。继承Inheritance == 难以在后来修改(无弹性代码)

   委托Delegation

委托是一个处理横切关注的好办法,委托和组合分享一个通用功能,但是我们需要在很多地方调用这个委托对象,显得繁琐。委托 == 繁琐

   AOP允许我们以模块化关注横向点并形成对象,称为Aspect,这样使用Aspect能够创建一个干净解耦的代码。

AOP相关概念

  1. Concerns关注 – 这是基于功能的模块部分,有两种类型关注:. 1. 核心关注 2. 跨切面关注(Aspect). 核心关注是有关业务逻辑,比如生成工资单,让员工记录,做银行转帐。跨切面关注是配合业务的一些活动任务,如日志 缓存等。
  2. Joinpoint连接点 – Joinpoint是在执行时的切入点,Aspect也就是跨切面关注的一些功能要加入主要业务功能的地方,一个连接点可以是一个被调用的方法。
  3. Advice建议 – 每个Aspect都有一个目标,它的任务是什么,这个任务会被切入到哪个连接点,这些都被称为Advice. Advice能够定义Aspect什么时候执行任务,是在核心关注也就是主要业务活动的之前 之后或者前后执行?
  4. Pointcut 切入点– 一个系统有很多连接点,但是并不是所有连接点都需要被选择切入Aspect的,Aspect从切入点能够获得帮助,选择哪个连接点介入。
  5. Aspect方面 – Advice 和 Pointcut定义了一个方面Aspect.Advice定义了Aspect的任务和什么时候执行它,而切入点Pointcut定义在哪里具体地方切入,也就是说,Aspect定义了它是什么东西 什么时候切入和在哪里切入。
  6. Target目标 – 目标是一个被切入的地方,它一般是核心关注,业务功能。
  7. Proxy代理 – 当一个advice应用到目标对象时,这时一个代理对象将被创建. AOP容器创建和管理代理对象的生命周期。
  8. Weaving织入 – Weaving是一个混合横向方面到目标业务对象的过程,织入可以是在编译时间,也可以在运行时间使用classload,Spring AOP缺省是在运行时间。

 

下面以Cache为例子说明AOP使用:

package com.aranin.spring.aop;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

public class MyCache {

    private LinkedHashMap<String, Object> cacheMap = new  LinkedHashMap<String, Object>();
    private LinkedHashMap<String, Date> timeStampMap = new  LinkedHashMap<String, Date>();
    /**
     * defines the max size of hashmap
     */
    private long maxsize = 10;  //should come from properties file or some configuration
    /**
     * how long the object should be stored before it is evicted from cache
     */
    private long objectLifeTime = 10000;

    private boolean lock = false;

    public LinkedHashMap<String, Object> getCacheMap() {
        return cacheMap;
    }

    public void setCacheMap(LinkedHashMap<String, Object> cacheMap) {
        this.cacheMap = cacheMap;
    }

    public LinkedHashMap<String, Date> getTimeStampMap() {
        return timeStampMap;
    }

    public void setTimeStampMap(LinkedHashMap<String, Date> timeStampMap) {
        this.timeStampMap = timeStampMap;
    }

    public long getMaxsize() {
        return maxsize;
    }

    public void setMaxsize(long maxsize) {
        this.maxsize = maxsize;
    }

    public long getObjectLifeTime() {
        return objectLifeTime;
    }

    public void setObjectLifeTime(long objectLifeTime) {
        this.objectLifeTime = objectLifeTime;
    }

    public boolean isLock() {
        return lock;
    }

    public void setLock(boolean lock) {
        this.lock = lock;
    }

    /**
     * This method is used to retrive the object from cache
     * @param key
     * @return
     */
    public Object get(String key){
        return this.getCacheMap().get(key);
    }

    /**
     * this method is used for putting an object in cache
     * @param key
     * @param object
     */
    public void put(String key, Object object){
        //get the curr date
        Date date = new Date(System.currentTimeMillis());
        //set object in cacheMap
        this.getCacheMap().put(key,object);
        //put timestamp in cache
        this.getTimeStampMap().put(key, date);
    }

    public void delete(String key){
        this.getCacheMap().remove(key);
        this.getTimeStampMap().remove(key);
    }

    public void clearAll(){
        this.setCacheMap(new  LinkedHashMap<String, Object>());
        this.setTimeStampMap(new  LinkedHashMap<String, Date>());
    }

    /**
     * remove last 2 entries
     * not worried about object life time
     * this is just an example
     */
    public void resize(){
        System.out.println("inside resize");
        long size = this.getCacheMap().size();
        System.out.println("size + " + size);
        if(size == this.getMaxsize()){
            System.out.println("max size has reached");
            Map.Entry<String, Date> firstEntry = this.getTimeStampMap().entrySet().iterator().next();
            System.out.println("removing : " + firstEntry.getKey() + " value : " + firstEntry.getValue());

            this.timeStampMap.remove(firstEntry.getKey());

            Map.Entry<String, Object> firstCEntry = this.getCacheMap().entrySet().iterator().next();
            System.out.println("removing : " + firstCEntry.getKey() + " value : " + firstCEntry.getValue());
            this.cacheMap.remove(firstCEntry.getKey());
        }
        System.out.println("leaving resize with size : " + this.getCacheMap().size());
    }
}

Advice代码:

package com.aranin.spring.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class ResizeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
          System.out.println("invoking " + method.getName() + " on " + target.getClass() + " Object");
          if(method.getName().equals("put")){
              System.out.println("before invoking " + method.getName());

              ((MyCache)target).resize();
          }
    }
}

配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="

http://www.springframework.org/schema/beans

 

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

 

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <bean id="resizeAdvice" class="com.aranin.spring.aop.ResizeAdvice" />

    <bean id="myCache" class="com.aranin.spring.aop.MyCache" />

    <bean id="myAOPCache"
                 class="org.springframework.aop.framework.ProxyFactoryBean">

      <property name="target" ref="myCache" />

      <property name="interceptorNames">
         <list>
            <value>resizeAdvice</value>
         </list>
      </property>
   </bean>
</beans>

设定了myCache的拦截器是resizeAdvice,

客户端运行代码:

package com.aranin.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class MyCacheClient {
    public static void main(String[] args){
        ApplicationContext springcontext = new FileSystemXmlApplicationContext("D:/samayik/SpringDemos/src/main/resources/springaopdemo.xml");

        MyCache myCache = (MyCache)springcontext.getBean("myAOPCache");

        myCache.put("1", "1");
        myCache.put("2", "2");
        myCache.put("3", "3");
        myCache.put("4", "4");
        myCache.put("5", "5");
        myCache.put("6", "6");
        myCache.put("7", "7");
        myCache.put("8", "8");
        myCache.put("9", "9");
        myCache.put("10", "10");
        System.out.println((String)myCache.get("1"));
        System.out.println((String)myCache.get("2"));
        System.out.println((String)myCache.get("10"));
        myCache.put("11", "11");
        System.out.println((String)myCache.get("1"));
        System.out.println((String)myCache.get("2"));
        System.out.println((String)myCache.get("10"));
        System.out.println((String)myCache.get("11"));

    }

}

AOP主题