spring来了-04-AOP
概述
- aspect object programming 面向切面编程
- 功能:可以实现“业务代码”与“关注点代码”分离
- 关注点代码:就是指重复执行的代码
- 业务代码:核心的业务功能
- 运行期间,执行核心业务代码的时候动态植入关注点代码【代理】
名词解释
- 关注点
- 重复代码就叫关注点
- 切面
- 关注点形成的类,就叫做切面(类)
- 切入点
- 执行目标对象方法,动态植入切面代码
- 可以通过切入点表达式,指定拦截哪些类的哪些方法,给指定的类在运行的时候植入切面类代码
- aop
- 面向切面编程,就是指 对很多功能都有的重复的代码的抽取,再在运行的时候往业务方法上动态植入“切面类代码”。
手动实现AOP编程
package cn.fuyi.d_myaop;
public interface IUserDao {
void save();
}
package cn.fuyi.d_myaop;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component("userDao")
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("=====已经保存数据====-");
}
}
package cn.fuyi.d_myaop;
import org.springframework.stereotype.Component;
/**
* 抽取重复代码形成的类
* @author fuyi
*
*/
@Component("aop") //加入IOC容器
public class Aop {
public void begin() {
System.out.println("开启事务");
}
public void commit() {
System.out.println("提交事务");
}
}
package cn.fuyi.d_myaop;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.Proxy;
public class ProxyFactory {
private static Object target;
private static Aop aop;
public static Object getProxyInstance(Object target_, Aop aop_) {
target = target_;
aop = aop_;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
aop.begin();
//执行目标对象方法
Object returnValue = method.invoke(target, args);
aop.commit();
return returnValue;
}
});
}
}
bean.xml
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.fuyi.d_myaop"></context:component-scan>
<!-- 调用工厂方法,返回UserDao的代理对象 -->
<bean id="userDao_proxy" class="cn.fuyi.d_myaop.ProxyFactory" factory-method="getProxyInstance">
<constructor-arg index="0" ref="userDao"></constructor-arg>
<constructor-arg index="1" ref="aop"></constructor-arg>
</bean>
package cn.fuyi.d_myaop;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
private ApplicationContext ac = new ClassPathXmlApplicationContext("cn/fuyi/d_myaop/beans.xml");
@Test
public void testAop1() throws Exception {
IUserDao ud = (IUserDao) ac.getBean("userDao_proxy");
ud.save();
}
}
/**Output
开启事务
=====已经保存数据====-
提交事务
*/
注解方式实现AOP编程
步骤:
1) 先引入aop相关jar文件 (aspectj aop优秀组件)
spring-aop-3.2.5.RELEASE.jar 【spring3.2源码】
aopalliance.jar 【spring2.5源码/lib/aopalliance】
aspectjweaver.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar 【spring2.5源码/lib/aspectj】或【aspectj-1.8.2\lib】
注意: 用到spring2.5版本的jar文件,如果用jdk1.7可能会有问题。需要升级aspectj组件,即使用aspectj-1.8.2版本中提供jar文件提供。
2) bean.xml中引入aop名称空间
3) 开启aop注解
4) 使用注解
@Aspect 指定一个类为切面类
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入点表达式
@Before("pointCut_()") 前置通知: 目标方法之前执行
@After("pointCut_()") 后置通知:目标方法之后执行(始终执行)
@AfterReturning("pointCut_()") 返回后通知: 执行方法结束前执行(异常不执行)
@AfterThrowing("pointCut_()") 异常通知: 出现异常时候执行
@Around("pointCut_()") 环绕通知: 环绕目标方法执行
package cn.fuyi.e_annoaop;
public interface IUserDao {
void save();
}
package cn.fuyi.e_annoaop;
import org.springframework.stereotype.Component;
@Component("userDao")
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("=====已经保存数据====-");
}
}
@Component
@Aspect // 指定当前类为切面类
public class Aop {
// 指定切入点表单式: 拦截哪些方法; 即为哪些类生成代理对象
@Pointcut("execution(* cn.fuyi.e_annoaop.*.*(..))")
public void pointCut_(){
}
// 前置通知 : 在执行目标方法之前执行
@Before("pointCut_()")
public void begin(){
System.out.println("开始事务/异常");
}
// 后置/最终通知:在执行目标方法之后执行 【无论是否出现异常最终都会执行】
@After("pointCut_()")
public void after(){
System.out.println("提交事务/关闭");
}
// 返回后通知: 在调用目标方法结束后执行 【出现异常不执行】
@AfterReturning("pointCut_()")
public void afterReturning() {
System.out.println("afterReturning()");
}
// 异常通知: 当目标方法执行异常时候执行此关注点代码
@AfterThrowing("pointCut_()")
public void afterThrowing(){
System.out.println("afterThrowing()");
}
// 环绕通知:环绕目标方式执行
@Around("pointCut_()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前....");
pjp.proceed(); // 执行目标方法
System.out.println("环绕后....");
}
}
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.fuyi.e_annoaop"></context:component-scan>
<!-- 开启aop注解方式,可不写
proxy-target-class 默认为false,如果目标对象实现了接口,就使用JDK代理,否则用Cglib代理
-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
public class App {
ApplicationContext ac =
new ClassPathXmlApplicationContext("cn/itcast/e_aop_anno/bean.xml");
// 目标对象有实现接口,spring会自动选择“JDK代理”
@Test
public void testApp() {
IUserDao userDao = (IUserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());
userDao.save();
}
// 目标对象没有实现接口, spring会用“cglib代理”
@Test
public void testCglib() {
OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
}
XML方式实现AOP编程
1) 引入jar文件 【aop 相关jar, 4个】
2) 引入aop名称空间
3)aop 配置
* 配置切面类 (重复执行代码形成的类)
* aop配置
拦截哪些方法 / 拦截到方法后应用通知代码
<?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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- dao 实例 -->
<bean id="userDao" class="cn.itcast.f_aop_xml.UserDao"></bean>
<bean id="orderDao" class="cn.itcast.f_aop_xml.OrderDao"></bean> <!-- 切面类 -->
<bean id="aop" class="cn.itcast.f_aop_xml.Aop"></bean> <!-- Aop配置 -->
<aop:config>
<!-- 定义一个切入点表达式: 拦截哪些方法 -->
<aop:pointcut expression="execution(* cn.itcast.f_aop_xml.*.*(..))" id="pt"/>
<!-- 切面 -->
<aop:aspect ref="aop">
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pt"/>
<!-- 前置通知: 在目标方法调用前执行 -->
<aop:before method="begin" pointcut-ref="pt"/>
<!-- 后置通知: -->
<aop:after method="after" pointcut-ref="pt"/>
<!-- 返回后通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<!-- 异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt"/> </aop:aspect>
</aop:config>
</beans>
切入点表达式
可以对指定的“方法”进行拦截; 从而给指定的方法所在的类生层代理对象。
<?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:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- dao 实例 -->
<bean id="userDao" class="cn.itcast.g_pointcut.UserDao"></bean>
<bean id="orderDao" class="cn.itcast.g_pointcut.OrderDao"></bean> <!-- 切面类 -->
<bean id="aop" class="cn.itcast.g_pointcut.Aop"></bean> <!-- Aop配置 -->
<aop:config> <!-- 定义一个切入点表达式: 拦截哪些方法 -->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.*.*(..))" id="pt"/>--> <!-- 【拦截所有public方法】 -->
<!--<aop:pointcut expression="execution(public * *(..))" id="pt"/>--> <!-- 【拦截所有save开头的方法 】 -->
<!--<aop:pointcut expression="execution(* save*(..))" id="pt"/>--> <!-- 【拦截指定类的指定方法, 拦截时候一定要定位到方法】 -->
<!--<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..))" id="pt"/>--> <!-- 【拦截指定类的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..))" id="pt"/>--> <!-- 【拦截指定包,以及其自包下所有类的所有方法】 -->
<!--<aop:pointcut expression="execution(* cn..*.*(..))" id="pt"/>--> <!-- 【多个表达式】 -->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
<!-- 下面2个且关系的,没有意义 -->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) && execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
<!--<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>--> <!-- 【取非值】 -->
<!--<aop:pointcut expression="!execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
spring来了-04-AOP的更多相关文章
- Spring 框架基础(04):AOP切面编程概念,几种实现方式演示
本文源码:GitHub·点这里 || GitEE·点这里 一.AOP基础简介 1.切面编程简介 AOP全称:Aspect Oriented Programming,面向切面编程.通过预编译方式和运行期 ...
- Spring的IOC和AOP之深剖
今天,既然讲到了Spring 的IOC和AOP,我们就必须要知道 Spring主要是两件事: 1.开发Bean:2.配置Bean.对于Spring框架来说,它要做的,就是根据配置文件来创建bean实例 ...
- Spring(6)—— AOP
AOP(Aspect-OrientedProgramming)面向切面编程,与OOP完全不同,使用AOP编程系统被分为切面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...
- 转-Spring Framework中的AOP之around通知
Spring Framework中的AOP之around通知 http://blog.csdn.net/xiaoliang_xie/article/details/7049183 标签: spring ...
- spring的IOC和AOP
spring的IOC和AOP 1.解释spring的ioc? 几种注入依赖的方式?spring的优点? IOC你就认为他是一个生产和管理bean的容器就行了,原来需要在调用类中new的东西,现在都是 ...
- spring之初识Ioc&Aop
Spring框架的作用 spring是一个轻量级的企业级框架,提供了ioc容器.Aop实现.dao/orm支持.web集成等功能,目标是使现有的java EE技术更易用,并促进良好的编程习惯. Spr ...
- [置顶] 深入浅出Spring(三) AOP详解
上次的博文深入浅出Spring(二) IoC详解中,我为大家简单介绍了一下Spring框架核心内容中的IoC,接下来我们继续讲解另一个核心AOP(Aspect Oriented Programming ...
- Spring学习笔记4——AOP
AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...
- Spring 的IOC和AOP总结
Spring 的IOC和AOP IOC 1.IOC 许多应用都是通过彼此间的相互合作来实现业务逻辑的,如类A要调用类B的方法,以前我们都是在类A中,通过自身new一个类B,然后在调用类B的方法,现在我 ...
- Spring中IOC和AOP的详细解释(转)
原文链接:Spring中IOC和AOP的详细解释 我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入,和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂 ...
随机推荐
- strtr介绍
strtr — 转换指定字符 string strtr ( string $str , string $from , string $to ) string strtr ( string $str , ...
- Keepalive
https://en.wikipedia.org/wiki/Keepalive Description A keepalive signal is often sent at predefined i ...
- Create XO Checker Game With Oracle Forms
Created XO Checker game in Oracle Forms and sharing its FMB (source code) for reference so that you ...
- Java编程思想读书笔记
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- ABAP Util代码
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- How to crack interviews ...
Code practice: Leetcode: www.leetcode.com HackerRank: www.hackerrank.com Topcoder: https://www.topco ...
- APP前端公共测试点
- NS_ASSUME_NONNULL_BEGIN,NS_ASSUME_NONNULL_END
Nonnull区域设置(Audited Regions) 如果需要每个属性或每个方法都去指定nonnull和nullable,是一件非常繁琐的事.苹果为了减轻我们的工作量,专门提供了两个宏:NS_AS ...
- [转]产品需求文档(PRD)的写作
产品需求对产品研发而言非常重要,写不好需求,后面的一切工作流程与活动都会受到影响.转载一篇文章,关于产品需求文档写作方面的,如下: 本文摘自(一个挺棒的医学方面专家):http://www.cnblo ...
- SAP研究贴之--发票校验提示移动平均价为负
近日,应付岗密集出现发票校验时移动平均价为负值导致过账失败的情况,采购经理又是拍桌子.又是摔杯子的.财务经理安排任务彻底清查,找出问题原因.哎,毫无头绪啊...测试机模拟业务吧流程:合同(系统外)-采 ...