Spring4 学习系列之——AOP的初解

在学习AOP之前,我们先简单理解下IOCAOP的原理。

IOC:控制反转

简单明白什么是控制反转

传统的面向对象编程是在一个类里需要哪个对象就new一个,new多了,就会造成各个类彼此之间的依赖性很高,甚至会造成一个对象出了个问题,导致其他类对象都不能运行的情况。所以这就是所谓的耦合度很高。

那么肯定需要一个方法来解耦啦,那就是ioc,ioc它是一个容器,在容器里存放的是bean对象,那么一个类要成为ioc内置的bean对象,需要在java类里面加入相关的注解声明,有了这个声明,ioc容器加载时就会全权管理这个类对象的一切,包括生命周期,也可以理解ioc是beanFactory的升级版,我们知道,beanFactory通常是在需要的类里直接静态或者继承关系来获得beanFactory里面的对象或者方法的,这种方法的依赖性还是有的,那么作为它的升级版ioc,那就不一样了,它可以说完全不依赖任何java文件,而是哪个java类需要某个对象,直接注入提供给他,极大的降低了耦合度。

DI:依赖注入。其实和IOC是一个原理,它只是基于IOC思想的一个实现

依赖注入有三种方法

  1. set方法
  2. 构造器
  3. 接口(不推荐)

依赖注入很简单,不做描述,一般都是配置自动扫描,然后自动注入@autowrite

 

AOP:面向切面

说实话也是ioc思想的衍生,面向对象完善,是一个很值得研究深透的一个思想。具体东西不说,直接简单点解释。在开发中,比如要做一个日志监控功能,功能要求每个方法前后都要后台打印执行的开始,结束时间,我们可以写一个接口或者继承来实现,但总管这样,效率依旧很低。我们可以这样子想:既然这些方法都要一个日志功能,传统的面向接口不太好,那么我们就用aop面向切面吧! 把日志功能当成一个切面,而这个切面是由许多切点构成的,想一下:很多个点,然后就成了一个面。。但是这些点的业务需求是一样的,只是实现不一样,否则有其他的点混入进来,这个“面”就不完美了,不完美那就不提倡了。那么什么是点呢?点就是连接点,一个方法里前后加入日志功能,那么它就有两个点,一前一后,这两个点我们就可以在抽出来的那个所谓的 "面 "的类中插入日志功能,我们可以通过注解或者xml来插入,有5种插入顺序,下面的列子会看到,其内部通过java的动态代理来实现,好,上个经典的例子。。

 

配置文件

        <!-- 自动扫描 -->
        <context:component-scan base-package="aop"></context:component-scan>
        <!-- 自动代理 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

 

有两个类:一个接口:ArithmeticCalculator     一个实现:ArithmeticCalculatorImpl

接口定义了简单的加减乘除

public interface ArithmeticCalculator {

    int add(int i, int j);
    int sub(int i, int j);
    
    int mul(int i, int j);
    int div(int i, int j);
    
}

接口的实现,返回结果

@Component
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {

    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }

}
 

接下来  我要在每个方法里前后,或者出现异常的时候都打印日志,因为这些功能都是相同的,而且每个方法里都有接入点,所以就组成一个切面类:AspectjTest.class

@Component // 加入到ioc容器中,让其自动扫描
@Aspect // 声明为一个切面
public class AspectjTest {
    // 前置通知,在目标方法开始前执行
    @Before(value = "execution(int aop.ArithmeticCalculatorImpl.*(int, int))")
    public void beforeMthod(JoinPoint joinpoint) {
        String methodName = joinpoint.getSignature().getName();
        Object[] args = joinpoint.getArgs();
        List<Object> largs = (List) Arrays.asList(args);
        System.out.println("the methood " + methodName + " begins with " + largs);
    }
    
    //后置通知,在目标方法执行完成后,无论结果有没有异常,都会执行的一个通知
    //在后置通知里还不能访问目标方法的结果
    @After(value="execution(int aop.ArithmeticCalculatorImpl.*(int, int))")
    public void afterMethod(JoinPoint joinpoint){
        String methodName = joinpoint.getSignature().getName();
        System.out.println("the methood " + methodName + " ends");
    }
    
    //运行结束通知,在目标方法正常执行完成后的一个通知
    //可以访问到返回结果
    @AfterReturning(value="execution(int aop.ArithmeticCalculatorImpl.*(int, int))",returning="result")
    public void afterReturnRunMethod(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("the methood " + methodName + " ends with: "+result);
    }
    
    //异常通知,在目标方法执行时发生异常返回的一个通知
    //可以访问到异常结果
    @AfterThrowing(value="execution(int aop.ArithmeticCalculatorImpl.*(int, int))",throwing="expection")
    public void afterThrowingMethod(JoinPoint joinPoint,Object expection){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("the methood "+methodName+" throw: "+expection    );
    }
    
    //环绕通知:需携带ProceedingJoinPoint类型的参数
    //环绕通知类似动态代理的全过程,ProceedingJoinPoint 类型的参数可以决定是否执行目标方法
    //环绕通知必须有返回值,返回值为目标方法的返回值
    
    @Around(value="execution(int aop.ArithmeticCalculatorImpl.*(int, int))")
    public Object aroundMethod(ProceedingJoinPoint pjp){
        String methodName = pjp.getSignature().getName();
        Object result = null;
        try {
            //前置通知
            System.out.println("the methood " + methodName + " begins with " +Arrays.asList(pjp.getArgs()));
            //执行目标方法
            result = pjp.proceed();
            //运行结束通知(正常结束)
            System.out.println("the methood " + methodName + " ends with: "+result);
        } catch (Throwable e) {
            //异常通知
            System.out.println("the methood "+methodName+" throw: "+e);
        }
        
        //后置通知(不管有没有异常都会返回)
        System.out.println("the methood " + methodName + " ends");
        return result;
    }
}
 

客户端测试下:

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        ArithmeticCalculator ar = (ArithmeticCalculator) ctx.getBean("arithmeticCalculatorImpl");
        int result = ar.add(1, 2);
        System.out.println("result:"+result);
        
        int result2 = ar.div(3, 1);
        System.out.println("result2:"+result2);
    }

}
 

观察控制台,结合上述,便能理解AOP的美妙之处

转载于:https://my.oschina.net/u/2509896/blog/780320

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值