框架学习之Spring学习(四)

Spring学习(四)

第四章 Spring的aop、代理模式(静态代理和动态代理)


文章目录


一、aop

Spring框架的AOP机制可以让开发者把业务流程中的通用功能抽取出来,单独编写功能代码。在业务流程执行过程中,Spring框架会根据业务流程要求,自动把独立编写的功能代码切入到流程的合适位置。

<!--开启包扫描-->
  <context:component-scan base-package="com.colin.aop"/>

  <!--进行aop配置-->
  <aop:config>
    <aop:aspect ref="logAspect">
      <!--在哪些位置加入相应的Aspect-->
      <aop:pointcut id="logPointCut" expression="execution(* com.colin.aop.*.insert*(..)) ||
        execution(* com.colin.aop.*.delete*(..)) ||
        execution(* com.colin.aop.*.update*(..))"/>
      <!--通知类型-->
<!--      <aop:before method="before" pointcut-ref="logPointCut"/>-->
<!--      <aop:after method="after" pointcut-ref="logPointCut"/>-->
<!--      <aop:after-throwing method="throwing" pointcut-ref="logPointCut"/>-->
      <aop:around method="around" pointcut-ref="logPointCut"/>
    </aop:aspect>
  </aop:config>
@Component
@Aspect // 让当前类为通知所在的类
public class LogAspect {
    /*@Before("execution(* com.colin.aop1.*.insert*(..)) ||" +
            "execution(* com.colin.aop1.*.delete*(..)) ||" +
            "execution(* com.colin.aop1.*.update*(..))")
    public void before() {
        Logger.info("前置通知输出");
    }*/

   /* @After("execution(* com.colin.aop1.*.insert*(..)) ||" +
            "execution(* com.colin.aop1.*.delete*(..)) ||" +
            "execution(* com.colin.aop1.*.update*(..))")*/
    /*@After("xxx()")
    public void after() {
        Logger.info("after通知输出");
    }*/

    @Around("xxx()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Logger.info("环绕之前");
        proceedingJoinPoint.proceed();
        Logger.info("环绕之后");
    }

    @Pointcut("execution(* com.colin.aop1.*.insert*(..)) ||" +
            "execution(* com.colin.aop1.*.delete*(..)) ||" +
            "execution(* com.colin.aop1.*.update*(..))")
    public void xxx() {

    }

二、代理模式

代理模式:代理模式是为另一个对象提供一个替身来控制对这个对象的访问。代理类负责为这个对象预处理消息,过滤消息并转发消息,以及进行消息被该对象执行后的后续处理。

按照代理类的创建时期,可分为静态代理和动态代理。

  1. 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
  2. 动态:在程序运行时运用反射机制动态创建而成。

1.静态代理

代码如下:

public interface PersonDao {
    void insertPerson();
}
public class PersonDaoImpl implements PersonDao {
    @Override
    public void insertPerson() {
//        System.out.println("事务的开启");
        // 在方法执行之前,增加日志,或者事务管理
        // 在方法体中有某些代码,主要的作用就是为了进行用户的新增
        System.out.println("插入用户");

        // 方法执行之后,在增加日志,如果插入成功,提交事务。如果插入失败,则事务回滚
//        System.out.println("事务的提交");
    }
}
public class PersonProxy implements PersonDao {
    PersonDao personDao;    // 被代理对象
    Transaction transaction;    // 事务类对象

    public PersonProxy(PersonDao personDao, Transaction transaction) {
        this.personDao = personDao;
        this.transaction = transaction;
    }

    @Override
    public void insertPerson() {
        transaction.beginTransaction();
        // 被代理对象真正要执行的内容
        personDao.insertPerson();
        transaction.commit();
    }
}

静态代理类优缺点

优点:

代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合)。

缺点:

1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。

2.动态代理

代码如下:

public class Transaction {
    public void beginTransaction() {
        System.out.println("事务的开启");
    }

    public void commit() {
        System.out.println("事务的提交");
    }
}
public class JDKInterceptor implements InvocationHandler {
    Object target;  // 被代理对象
    Transaction transaction;    // 事务相关的属性

    public JDKInterceptor(Object target, Transaction transaction) {
        this.target = target;
        this.transaction = transaction;
    }

    /**
     *
     * @param proxy 目标对象的代理类实例
     * @param method 对应于在代理实例上调用接口方法的Method实例
     * @param args 传入到代理实例上方法参数值的对象数组
     * @return 方法的返回值,没有返回值则为null
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 获取被代理对象执行方法的方法名
        String methodName = method.getName();
        // 判断是否为增删改方法
        if ("insertPerson".equals(methodName) ||
                "deletePerson".equals(methodName) ||
                "updatePerson".equals(methodName)) {
            transaction.beginTransaction();
            // 调用真正的方法
            method.invoke(target);
            transaction.commit();
        } else {
            // 查询方法不需要增加事务
            method.invoke(target);
        }
        return null;
    }
}

动态代理的优点

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。


总结

以上就是今天要讲的内容。

上一篇:类微信界面设计


下一篇:spring事务详解(三)源码详解