Spring进阶之AOP编程

本文介绍面向切面编程(AOP)的基本概念与Spring框架中的应用实践。包括AOP的起源、核心思想及其与面向对象编程(OOP)的关系,并通过具体案例演示了Spring AOP中的五种增强类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一)AOP【面向切面编程】
    (1)AOP的起源
         来AOP看来,任何的程序都是由服务代码和业务代码组合而成
         来AOP看来,程序员应该只关注业务代码,而不要关注服务代码
         来AOP看来,程序中所有服务代码交由spring容器搞定,业务代码交由程序员搞定
         来AOP看来,业务代码必须要与服务代码共同存在,表面上分隔,但实际上是一个整体
   
    (2)什么是AOP
         AOP是一种将业务代码和服务代码分离的设计思想,
         但最终通过代理方式整合在一起的技术         
   
    (3)AOP能解决什么问题
         程序员只关注业务代码,所有的服务代码,都是通过配置的方式解决


    (4)AOP思想和本质
         思想:分离思想
         本质:通过代理实现
 
    (5)OOP与AOP的地位
         OOP:它是一个静态概念,OOP还是主流,项目中OOP为主。
         AOP:它是一个动态概念,OOP还是支流,项目中AOP为辅。
         总之:OOP和AOP是一个互补的技术,不是替代关系


    (6)AOP术语
        (A)连接点:一个类中所有的业务方法,叫连接点
        (B)切入点:一个类中的某业务方法,符合一条件时,该业务方法就是切入点
        (C)增强【advice】含有服务代码的类
        (D)切面【aspect】:等价于切入点 + 增强
        (E)目标对象:有真正业务功能的对象,例如:UserDao

        (F)代理对象:是目标对象在非业务功能之外的对象,例如:事务处理,异常信息显示,日志。

二)springAOP中的五种增强类型【UserDao中的addUser()为例】 
   (A)前置增强【before】

   (B)后置增强【after】

如果业务代码出错,后置增强依然会执行
   (C)方法返回后增强【after-returning】
        如果业务代码出错,方法返回后增强不会执行

   (D)方法抛异常后增强【after-throwing】
        如果业务代码出错,方法抛异常后增强会执行,反之,不会执行

   (E)方法环绕增强【around】
        如果业务代码出错,方法环绕增强的后半部份不会执行

三)springAOP开发环境
   (1)导入jar包
        >>spring.jar/commons-logging.jar
  
        >>aspectjweaver.jar
/aspectjrt.jar/
cglib-nodep-2.1_3.jar
   (2)XML声明
   (3)execution切入点表达式
参见:<<关于execution表达式中各部分的含义说明.txt>>
<!-- 配置AOP【重点】 -->
<aop:config>
<aop:pointcut 
                     id="xxxx【标识符】" 
                     expression="execution(public void 包名.addUser())"/>(在包名.addUser()中可以省略包名,因为addUser方法是在spring容器中寻找addUser方法)
                     【表示切入点的条件】
<aop:aspect ref="serviceBeanID">
                       【表示增强的ID值】    
<aop:before method="addUser" pointcut-ref="xxxx"/>
                       【前置增强】
                       【执行哪个服务方法】
                       【引用哪个切入点的条件】 
</aop:aspect>
</aop:config>


   (4)springAOP的工作过程
       (1)启动容器时,创建目标对象和增强对象
       (2)<aop:config/>,通过cglib创建代理对象,是目标对象的代理,运行时产生
       (3)程序员-代理对象-writeLog()-目标对象-addUser()-代理对象
        总结:该过程是spring容器内部完成,使用动态代理技术。      

接下来写一个实例认识aop编程:

(1)前置通知类型:

配置文件applicationContext.ml

<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
		xsi:schemaLocation="
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<!-- 目标对象 -->
	<bean id="userDao" class="com.spring.demo.UserDao"></bean>
	<!-- 增强对象 -->
	<bean id="serviceBean" class="com.spring.demo.ServiceBean"></bean>
	<!-- 前置增强 -->
	<aop:config>
		<aop:pointcut id="add" expression="execution(public void com.spring.demo.UserDao.addUser())" /><!-- 把连接点变为切入点 -->
		<aop:aspect ref="serviceBean">
			<aop:before method="writeLog" pointcut-ref="add"/>
		</aop:aspect>
	</aop:config>
</beans>

两个bean类:UserDao,ServiceBean

package com.spring.demo;

public class UserDao {

	public UserDao(){}
	
	public void addUser(){
		System.out.println("添加用户");
	}
}

package com.spring.demo;

public class ServiceBean {

	public ServiceBean(){}
	public void writeLog(){
		System.out.println("写日志");
	}
}

测试类:

package com.spring.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ApplicationContext ac=new ClassPathXmlApplicationContext(new String[]{"com/spring/demo/applicationContext.xml"});
		UserDao dao= (UserDao) ac.getBean("userDao");
		dao.addUser();
	}

}

运行结果:

2014-7-10 9:02:05 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@b42cbf: display name [org.springframework.context.support.ClassPathXmlApplicationContext@b42cbf]; startup date [Thu Jul 10 09:02:05 CST 2014]; root of context hierarchy
2014-7-10 9:02:05 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/spring/demo/applicationContext.xml]
2014-7-10 9:02:05 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@b42cbf]: org.springframework.beans.factory.support.DefaultListableBeanFactory@787d6a
2014-7-10 9:02:05 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@787d6a: defining beans [userDao,serviceBean,org.springframework.aop.config.internalAutoProxyCreator,add,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0]; root of factory hierarchy
写日志
添加用户

后置通知:

<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
		xsi:schemaLocation="
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<!-- 目标对象 -->
	<bean id="userDao" class="com.spring.demo.UserDao"></bean>
	<!-- 增强对象 -->
	<bean id="serviceBean" class="com.spring.demo.ServiceBean"></bean>
	<!-- aop配置 -->
	<aop:config>
		<aop:pointcut id="add" expression="execution(public void com.spring.demo.UserDao.addUser())" /><!-- 把连接点变为切入点 -->
		<aop:aspect ref="serviceBean">
			<!--<aop:before method="writeLog" pointcut-ref="add"/> 前置增强 -->
			<aop:after method="writeLog" pointcut-ref="add"/><!-- 后置增强 -->
		</aop:aspect>
	</aop:config>
</beans>

运行结果:


2014-7-10 9:47:47 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6f7ce9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@6f7ce9]; startup date [Thu Jul 10 09:47:47 CST 2014]; root of context hierarchy
2014-7-10 9:47:47 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/spring/demo/applicationContext.xml]
2014-7-10 9:47:48 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@6f7ce9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@1f82982
2014-7-10 9:47:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1f82982: defining beans [userDao,serviceBean,org.springframework.aop.config.internalAutoProxyCreator,add,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0]; root of factory hierarchy
添加用户
写日志

 (C)方法返回后增强【after-returning】:

<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
		xsi:schemaLocation="
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<!-- 目标对象 -->
	<bean id="userDao" class="com.spring.demo.UserDao"></bean>
	<!-- 增强对象 -->
	<bean id="serviceBean" class="com.spring.demo.ServiceBean"></bean>
	<!-- aop配置 -->
	<aop:config>
		<aop:pointcut id="add" expression="execution(public void com.spring.demo.UserDao.addUser())" /><!-- 把连接点变为切入点 -->
		<aop:aspect ref="serviceBean">
			<!--<aop:before method="writeLog" pointcut-ref="add"/> 前置增强 -->
			<!--<aop:after method="writeLog" pointcut-ref="add"/> 后置增强 -->
		    <aop:after-returning method="writeLog" pointcut-ref="add"/>
		</aop:aspect>
	</aop:config>
</beans>

E)方法环绕增强【around】

配置文件:

<?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
		xsi:schemaLocation="
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
	<!-- 目标对象 -->
	<bean id="userDao" class="com.spring.demo.UserDao"></bean>
	<!-- 增强对象 -->
	<bean id="serviceBean" class="com.spring.demo.ServiceBean"></bean>
	<!-- aop配置 -->
	<aop:config>
		<aop:pointcut id="add" expression="execution(public void com.spring.demo.UserDao.addUser())" /><!-- 把连接点变为切入点 -->
		<aop:aspect ref="serviceBean">
			<!--<aop:before method="writeLog" pointcut-ref="add"/> 前置增强 -->
			<!--<aop:after method="writeLog" pointcut-ref="add"/> 后置增强 -->
		   <!-- <aop:after-returning method="writeLog" pointcut-ref="add"/> -->
		   <aop:around method="both" pointcut-ref="add"/>
		</aop:aspect>
	</aop:config>
</beans>

增强对象的服务方法:

package com.spring.demo;

import org.aspectj.lang.ProceedingJoinPoint;

public class ServiceBean {

	public ServiceBean(){}
	public void writeLog(){
		System.out.println("写日志");
	}
	
	public void open(){
		System.out.println("打开数据库连接");
	}
	public void close(){
		System.out.println("关闭数据库连接");
	}
	/**
	 * 连接目标对象和代理对象的一个桥梁
	 * @param pj
	 * @throws Throwable 
	 */
	public void both(ProceedingJoinPoint pj) throws Throwable{
		open();
		pj.proceed();
		close();
	}
}
运行结果:
2014-7-10 10:19:46 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1960f05: display name [org.springframework.context.support.ClassPathXmlApplicationContext@1960f05]; startup date [Thu Jul 10 10:19:46 CST 2014]; root of context hierarchy
2014-7-10 10:19:46 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/spring/demo/applicationContext.xml]
2014-7-10 10:19:46 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@1960f05]: org.springframework.beans.factory.support.DefaultListableBeanFactory@914f6a
2014-7-10 10:19:46 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@914f6a: defining beans [userDao,serviceBean,org.springframework.aop.config.internalAutoProxyCreator,add,org.springframework.aop.aspectj.AspectJPointcutAdvisor#0]; root of factory hierarchy
打开数据库连接
添加用户
关闭数据库连接




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值