spring AOP实现原理实例

什么是AOP

  AOP的全称是Aspect Orient Programming,即面向切面编程。是对OOP(Object Orient Programming)的一种补充,战门用于处理一些具有横切性质的服务。常常用于日志输出、安全控制等。

优点:

1、降低模块之间的耦合度

2、使系统容易扩展

3、更好的代码复用。

AOP使用场景:
AOP用来封装横切关注点,具体可以在下面的场景中使用:

Authentication 权限

Caching 缓存

Context passing 内容传递

Error handling 错误处理

Lazy loading 懒加载

Debugging  调试

logging, tracing, profiling and monitoring 记录跟踪 优化 校准

Performance optimization 性能优化

Persistence  持久化

Resource pooling 资源池

Synchronization 同步

Transactions 事务

AOP相关概念:
切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
连接点(Joinpoint) :程序执行过程中的某一行为。
通知(Advice) :“切面”对于某个“连接点”所产生的动作。
切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
目标对象(Target Object) :被一个或者多个切面所通知的对象。
AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。


spring aop通知(advice)分成五类: 
前置通知[Before advice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。 
正常返回通知[After returning advice]:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。 
异常返回通知[After throwing advice]:在连接点抛出异常后执行。 
返回通知[After (finally) advice]:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。 
环绕通知[Around advice]:环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。

 

怎么在原来类的实现的基础上添加逻辑代码(在不修改源代码的情况下,可以实现功能的增强

刚开始说到是对OOP的一种补充,具体补充的是什么呢?考虑一种情况,如果我们需要在所有方法里打印一句日志。

按照OOP的处理思想,1>直接在源代码方法中加日志

2>在不修改源代码的情况下重写一个类,再编写一个日志打印

3>用继承,重写。在不修改源代码的情况下重新创建一个类,再编写一个日志打印,并调用源代码中的方法。这就是面向对象编程思想。

但是如果要求我们在业务方法开始或结束时再打印一些日志呢?看起来一个比一个简单,其实还是很繁琐,这样始终不是办法,而且我们总是在改业务方法,在业务方法里面掺杂了太多的其他操作,侵入性太高。

所以,我们可以用AOP

下面,简单写一个小例子
1>导包(在原有spring项目上,添加aspectj-1.8.9.jar和aspectjweaver-1.8.1.jar)

2>新建通知类MyAdvice.java

package cn.xxs.advice;

import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {

	/**
	 * 前置通知
	 * @param joinpoint
	 */
	public void before() {
		System.out.println("before");
	}
	/**
	 * 后置通知
	 */
	public void after() {
		System.out.println("after");
	}
	/**
	 * 引入通知
	 */
	public void afterReturning() {
		System.out.println("afterReturning");
	}
	/**
	 * 环绕通知
	 */
	public void around(ProceedingJoinPoint joinpoint) {
		System.out.println("around开始");
		try {
			joinpoint.proceed();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("around结束");
	}
	/**
	 * 异常通知
	 */
	public void afterThrowing() {
		System.out.println("afterThrowing");
	}
	
}

3>创建接口UserService.java

package cn.xxs.service;

public interface UserService {
	
	public void print();

}

4>创建接口的实现类UserServiceImpl.java

package cn.xxs.service.impl;


import cn.xxs.service.UserService;
import cn.xxs.util.BeanUtil;

public class UserServiceImpl implements UserService{

	@Override
	public void print() {
		
		System.out.println("打印");
	}

}

5>配置bean.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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/context/spring-tx.xsd
        ">    
  
     <!-- 把UserServiceImpl交给spring管理 -->
     <bean id="userService" class="cn.xxs.service.impl.UserServiceImpl"></bean> 
     
     <!-- 配置通知对象 -->
     <bean id="myAdvice" class="cn.xxs.advice.MyAdvice"></bean>
     
     <!-- 配置aop -->
      <aop:config>
      <!-- 配置切面,用于各种通知 -->
        <aop:aspect ref="myAdvice">
			<!-- 配置aop -->
			<!-- expression :配置加入的具体位置 -->
            <aop:pointcut  expression="execution(public * *(..))" id="myPointcut"/>
			<!-- 配置通知类型 -->
            <aop:before pointcut-ref="myPointcut" method="before"/>
            <aop:after pointcut-ref="myPointcut" method="after"/>
            <aop:after-returning pointcut-ref="myPointcut" method="afterReturning"/>
            <aop:around pointcut-ref="myPointcut" method="around"/>
            <aop:after-throwing pointcut-ref="myPointcut" method="afterThrowing"/>

        </aop:aspect>
    </aop:config>
     
    
</beans>  

6>创建测试代码UserAction.java

package cn.xxs.action;

import org.junit.Test;

import cn.xxs.service.UserService;
import cn.xxs.util.BeanUtil;

public class UserAction {
	
	private UserService userService;	
	
	@Test
	public void test() {
		
		userService = (UserService) BeanUtil.getBean("userService");	
		userService.print();
	}
}

7>创建工具类BeanUtil.java

package cn.xxs.util;


import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanUtil {
	
	public static Object getBean(String beanName) {
		return new ClassPathXmlApplicationContext("bean.xml").getBean(beanName);
	}
}

测试结果:

  • 2
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值