springAOP总结

       AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

      AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

springAOP在ssm框架中起到了解耦作用,一般用于性能检测、访问控制、事务管理、缓存、对象池管理、日志记录等方面。

实现的关键在于AOP框架自动创建AOP代理,用到的设计模式有:工厂、单例、适配器、装饰器、代理、策略、模块、观察者。

AOP的底层实现是动态代理:JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
   
而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。这样讲一定很抽象,我们马上着手动用Proxy和InvocationHandler这两个魔法戒对上一节中的性能监视代码进行AOP式的改造。

一 AOP的基本概念

(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用

(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

二 通知类型介绍

(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可

(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值

(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名

来访问目标方法中所抛出的异常对象

(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式

(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

先用一个实例来简单介绍:

aop.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"
      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">
     <!--核心业务  -->
     <bean id="serviceA" class="services.ServiceA"></bean>
     <bean id="serviceB" class="services.ServiceB"></bean>
     <bean id="serviceC" class="services.ServiceC"></bean>
    
     <!--通知业务  -->
     <bean id="notice" class="notice.Notice"></bean>
     
     <!-- aop配置 -->
     <aop:config>
     <!--定义一个切面,切面里可以有多个切点,但如果切点在切面的外面,则该切点可以被它下面的所有切面所共享  -->
        <aop:aspect ref="notice">
        <!--定义一个切入点表达式  -->
        <aop:pointcut id="cutpoint" expression="execution(* services.*.*(..))"/>
        <!--在切入点前执行通知的方法  -->
        <aop:before method="beforeNotice" pointcut-ref="cutpoint" />
        <aop:after method="afterNotice" pointcut="execution(* services.ServiceC.*(..))"/>
        <aop:around method="aroundNotice" pointcut-ref="cutpoint"/>
        </aop:aspect>
     
     </aop:config>


</beans>

execution表达式:用来匹配执行方法的连接点

A:@Pointcut("execution(* com.aijava.springcode.service..*.*(..))")

第一个*表示匹配任意的方法返回值,..(两个点)表示零个或多个,上面的第一个..表示service包及其子包,第二个*表示所有类,第三个*表示所有方法,第二个..表示

方法的任意参数个数

通知类 

public class Notice {
	public void beforeNotice(){
		SimpleDateFormat simp = new SimpleDateFormat("yyyy-mm-dd hh:MM:ss");
		System.out.println(simp.format(new Date())+":做了一笔业务!!!");
	}
	public void afterNotice(){
		System.out.println("通知结束");
	}
	public void aroundNotice(ProceedingJoinPoint point){
		System.out.println("环绕开始");
		try {
			String name=point.getSignature().getName();
			System.out.println("方法名"+name);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("环绕结束");
	}
}

核心业务类,三个基本相同,列出一个

public class ServiceA {
	public void addAccount(){
		System.out.println("addaccount");
	}
}

unit4 测试类

public class Test1 {	
	@Test
	public void beforeNotice(){
		ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
		ServiceA serviceA = ctx.getBean("serviceA",ServiceA.class); 
		ServiceB serviceB = ctx.getBean("serviceB",ServiceB.class); 
		ServiceC serviceC = ctx.getBean("serviceC",ServiceC.class); 
		System.out.println("开始");
		serviceA.addAccount();
		serviceB.desposit();
		serviceC.withDraw();
	}

}

结果为:

开始
2018-19-23 03:08:17:做了一笔业务!!!
环绕开始
方法名addAccount
环绕结束
2018-19-23 03:08:17:做了一笔业务!!!
环绕开始
方法名desposit
环绕结束
2018-19-23 03:08:17:做了一笔业务!!!
环绕开始
方法名withDraw
环绕结束
通知结束

猜你喜欢

转载自blog.csdn.net/qq_39404258/article/details/81981411