Spring AOP 编程原理和实现

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

Spring AOP 编程原理和实现_第1张图片

 正如上图所示,UserDao和BookDao都需要开启和提交事务,而它们是必须的(通用的)且又和核心业务不相关,如何提高代码的复用性和开发效率,我们来看下图:

Spring AOP 编程原理和实现_第2张图片

我们将与业务代码不相关(或某功能的代码)从类中剥离出来,把它们定义在另一个类中,在使用是可以利用AOP对需要增强的代码进行织入,这个就是AOP的目的。

AOP的实现是基于代理实现的,代理又有静态代理和动态代理,静态代理不能适应变化,动态代理利用反射机制可以适应变化。

Spring默认采取的动态代理机制实现AOP,当动态代理不可用时(代理类无接口)会使用CGlib机制。

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
 

静态代理:

静态代理根据OCP原则是在代理对象和目标对象实现共同的接口,并且代理对象持有目标对象的引用。

模拟实现:DAO接口:

public interface IUserDao {

     void list();

     void add();
}

DAO实现类:

@Repository
public class UserDao implements IUserDao {
    @Override
    public void list() {
        System.out.println("user.....list");
    }

    @Override
    public void add() {
        System.out.println("user....add");
    }
}

增强功能类:

public class LogInfo {

    public static void logInfo(String operation){
        System.out.println("执行了"+operation+"操作!");
    }
}

静态代理类:代理DAO实现并实现增强功能(添加日志功能)

@Component(value = "userProxyDao")
public class UserProxyDao implements IUserDao {

    @Resource
    private IUserDao userDao;

    @Override
    public void list() {
        LogInfo.logInfo("list");
        this.userDao.list();
    }

    @Override
    public void add() {
       LogInfo.logInfo("add");
       this.userDao.add();
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/beans.xml")
public class UserDaoTest {

    @Resource(name = "userProxyDao")
    private IUserDao userDao;
    @Test
    public void test(){
        this.userDao.add();
        this.userDao.list();
    }
}

输出如下:

Spring AOP 编程原理和实现_第3张图片

以上的静态代理的问题时,当有多个业务类时,每个类都要创建一个代理类,显然这是不切实际的。我们可以通过Java的java.lang.reflect.InvocationHandler接口实现动态代理。

动态代理:通过代理对象来创建业务对象,在代理对象中完成对业务的增强(业务)的处理。

基于JDK的动态代理类:

package edu.song.aop.util;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理类
 */
public class ProxyLog implements InvocationHandler {

    private ProxyLog(){}
    private Object target;

    /**
     * 生成代理对象的方法
     * @param object(要代理的对象)
     * @return (目标对象---》代理对象)
     */
    public static Object getInstance(Object object){
        ProxyLog proxyLog= new ProxyLog();
        proxyLog.target=object;
        /**
         * 创建代理实例:
         * 参数1:代理对象的类加载器
         * 参数2:代理对象的接口
         * 参数3:实现InvocationHandler的对象
         * 返回的就是代理对象
         */
       Object result= Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),proxyLog);
        return result;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             //要增加(强)的功能代码
             LogInfo.logInfo(method.getName()+"!");
             //回调
             Object invoke = method.invoke(target, args);
             return invoke;
    }
}

DAO:

@Repository
public class UserDao implements IUserDao {
    @Override
    public void list() {
        System.out.println("user...dao..list");
    }

    @Override
    public void add() {
        System.out.println("user..dao..add");
    }
}

Service:

@Service
public class UserService implements IUserService{

     @Resource//(name = "proxyLogDao")
     private IUserDao userDao;

    @Override
    public void list() {
        System.out.println("user service....list");
        this.userDao.list();
    }

    @Override
    public void add() {
        System.out.println("user service.....add");
        this.userDao.add();
    }
}

  注意以上业务类代码的注释部分

配置文件:




     
     


     
         
     

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/beans.xml")
public class UserDaoTest {
    @Resource
    private IUserService userService;
    @Test
    public void test(){
        userService.add();
        userService.list();
    }
}

输出如下:

 Spring AOP 编程原理和实现_第4张图片

 以上输出并没有使用代理类,我们将业务代码修改如下:

@Service
public class UserService implements IUserService{

     @Resource(name = "proxyLogDao")
     private IUserDao userDao;

Spring AOP 编程原理和实现_第5张图片

 我们还可以在代理中设置条件等来完成特有功能,修改代理类如下:

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           if(method.getName().equals("list")) {
               //只有list方法要增加(强)的功能代码
               LogInfo.logInfo(method.getName() + "!");
           }
             //回调
             Object invoke = method.invoke(target, args);
             return invoke;
    }

spring框架的AOP实现提供了两种方式:分别是xml的配置和annotation的配置。接下来我们自定义一个注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation {
    String value() default "";
}

接口上添加自定义注解:

public interface IUserDao {

     @LogAnnotation("#### 列表 #####")
     void list();

     void add();
}

修改代理类,添加对注解的处理:

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
             if(method.isAnnotationPresent(LogAnnotation.class)){
                 LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
                 LogInfo.logInfo(annotation.value());
             }
             //回调
             Object invoke = method.invoke(target, args);
             return invoke;
    }

Spring AOP 编程原理和实现_第6张图片

 

你可能感兴趣的:(spring,java)