AOP的好处与之前DAO和DAOIMPL的对比

原始代码的写法

既然要通过代码来演示,那必须要有例子,这里我的例子为:

有一个接口Dao有insert、delete、update三个方法,在insert与update被调用的前后,打印调用前的毫秒数与调用后的毫秒数

首先定义一个Dao接口:

public interface Dao {

    public void insert(); public void delete(); public void update(); }

然后定义一个实现类DaoImpl:
public class DaoImpl implements Dao { @Override public void insert() { System.out.println("DaoImpl.insert()"); } @Override public void delete() { System.out.println("DaoImpl.delete()"); } @Override public void update() { System.out.println("DaoImpl.update()"); } }

最原始的写法,我要在调用insert()与update()方法前后分别打印时间,就只能定义一个新的类包一层,在调用insert()方法与update()方法前后分别处理一下
,新的类我命名为ServiceImpl,其实现为:
public class ServiceImpl {

    private Dao dao = new DaoImpl();

    public void insert() { System.out.println("insert()方法开始时间:" + System.currentTimeMillis()); dao.insert(); System.out.println("insert()方法结束时间:" + System.currentTimeMillis()); } public void delete() { dao.delete(); } public void update() { System.out.println("update()方法开始时间:" + System.currentTimeMillis()); dao.update(); System.out.println("update()方法结束时间:" + System.currentTimeMillis()); } }

这是最原始的写法,这种写法的缺点也是一目了然:

方法调用前后输出时间的逻辑无法复用,如果有别的地方要增加这段逻辑就得再写一遍 
如果Dao有其它实现类,那么必须新增一个类去包装该实现类,这将导致类数量不断膨胀。

使用AOP

最后来看一下使用AOP的方式,首先定义一个时间处理类,我将它命名为TimeHandler:

public class TimeHandler {
  public void printTime(ProceedingJoinPoint pjp) { Signature signature = pjp.getSignature(); if (signature instanceof MethodSignature) { MethodSignature methodSignature = (MethodSignature)signature; Method method = methodSignature.getMethod(); System.out.println(method.getName() + "()方法开始时间:" + System.currentTimeMillis());       try { pjp.proceed(); System.out.println(method.getName() + "()方法结束时间:" + System.currentTimeMillis()); } catch (Throwable e) {         e.printStackTrace(); } } } }
切面方法printTime本身可以不用定义任何的参数,但是有些场景下需要获取调用方法的类、方法签名等信息,此时可以
在printTime方法中定义JointPoint,Spring会自动将参数注入,可以通过JoinPoint获取调用方法的类、方法签名等信息
。由于这里我用的aop:around,要保证方法的调用,这样才能在方法调用前后输出时间,因此不能直接使用JoinPoint,
因为JoinPoint没法保证方法调用。此时可以使用ProceedingJoinPoint,ProceedingPointPoint的proceed()方法可以保
证方法调用,但是要注意一点,ProceedingJoinPoint只能和aop:around搭配,换句话说,如果aop.xml中配置的是aop:before,
然后printTime的方法参数又是ProceedingJoinPoint的话,Spring容器启动将报错。

接着看一下ApplicationContext.xml的配置:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
  <bean id="daoImpl" class="org.xrq.spring.action.aop.DaoImpl" />
   <bean id="timeHandler" class="org.xrq.spring.action.aop.TimeHandler" />
  <aop:config>
    <aop:pointcut id="addAllMethod" expression="execution(* org.xrq.spring.action.aop.Dao.*(..))" />
    <aop:aspect id="time" ref="timeHandler">
    <aop:before method="printTime" pointcut-ref="addAllMethod" />
    <aop:after method="printTime" pointcut-ref="addAllMethod" />
    </aop:aspect>
  </aop:config>
</beans>

测试代码很简单:
public class AopTest {

    @Test
    @SuppressWarnings("resource")
    public void testAop() { ApplicationContext ac = new ClassPathXmlApplicationContext("spring/aop.xml"); Dao dao = (Dao)ac.getBean("daoImpl"); dao.insert(); System.out.println("----------分割线----------"); dao.delete(); System.out.println("----------分割线----------"); dao.update(); } }
到此我总结一下使用AOP的几个优点:

  切面的内容可以复用,比如TimeHandler的printTime方法,任何地方需要打印方法执行前的时间与方法执行后的时间,都可以使用TimeHandler的printTime方法 
避免使用Proxy、CGLIB生成代理,这方面的工作全部框架去实现,开发者可以专注于切面内容本身 
代码与代码之间没有耦合,如果拦截的方法有变化修改配置文件即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值