1.Spring AOP 中的基本概念
a.连接点(Joinpoint)
在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
通俗讲:
层于层之间调用的过程中,目标层中可供调用的方法,就称之为连接点。
b.切入点(Pointcut)
匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
通俗讲:
在连接点的基础上 增加上切入规则 选择出需要进行增强的切入点 这些基于切入规则选出来的连接点 就称之为切入点。
c.切面(Aspect)
一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
通俗讲:
狭义上就是 当spring拦截下切入点后 讲这些切入点 交给 处理类 进行功能的增强,这个处理类就称之为切面。
广义上来讲 讲 spring底层的代理 切入点 和 处理类 加在一起 实现的 对层与层之间调用过程进行增强的机制 称之为切面。
d.通知(Advice)
在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
通俗讲:
在spring底层的代理拦截下切入点后,讲切入点交由切面类,切面类中就要有处理这些切入点的方法,这些方法就称之为通知(也叫增强 增强方法)。针对于切入点执行的过程,通知还分为不同的类型,分别关注切入点在执行过程中的不同的时机。
e.目标对象(Target Object)
被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
通俗讲:
就是真正希望被访问到的对象。spring底层的动态代理对他进行了代理,具体能不能真的访问到目标对象,或在目标对象真正执行之前和之后是否做一些额外的操作,取决于切面。
2.Spring的AOP入门案例
a.导入aop相关开发包
b.创建一个切面类
package cn.tedu.aop; import org.springframework.stereotype.Component; @Component public class FirstAspect { public void before(){ } }
c.定义通知(增强)
package cn.tedu.aop; import org.springframework.stereotype.Component; @Component public class FirstAspect { public void before(){ System.out.println("before..."); } }
d.定义一个连接点
AOPTest.java
package cn.tedu.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.tedu.service.UserService; public class AOPTest { @Test public void test01(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.addUser(); // 一个连接点 } }
UserService.java
package cn.tedu.service; public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); public void query(); }
UserServiceImple.java
package cn.tedu.service; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImple implements UserService { @Override public void addUser() { System.out.println("增加用户。。"); } @Override public void updateUser() { System.out.println("修改用户。。"); } @Override public void deleteUser() { System.out.println("删除用户。。"); } @Override public void query() { System.out.println("查询用户。。"); } }
e.配置切入点
在MyEclipse中导入aop的schema约束文件,以便于在配置文件中可以提示标签。
在其中配置切入点:
<aop:config> <!-- 配置切入点 --> <aop:pointcut expression="within(cn.tedu.service.UserServiceImple)" id="pc01"/> </aop:config>
f.定义切面
<aop:config> <!-- 配置切入点 --> <aop:pointcut expression="within(cn.tedu.service.UserServiceImple)" id="pc01"/> <!-- 配置切入面 --> <aop:aspect ref="firstAspect"> <aop:before method="before" pointcut-ref="pc01"/> </aop:aspect> </aop:config>
firstAspect:切面类
before:切面中的方法
pc01:该通知(增强)方法绑定的切入点
g.执行方法,发现切面确实起作用
before...
增加用户。。
3.切入点表达式
a.within表达式
(1)通过类名进行匹配
通过类名进行匹配 粗粒度的切入点表达式
within(包名.类名)
则这个类中的所有的方法都会别表达式识别,成为切入点。
expression="within(cn.tedu.service.UserServiceImple)"
(2)用 * 号匹配符
匹配指定包下所有的类,注意,只匹配当前包,不包括当前包的子孙包。
此处的 * 代表切除该包下的所有类
expression="within(cn.tedu.service.*)"
(3)用 * . * 号匹配符
匹配包
此处第一个 * 代表一层子目录,第二个 * 代表这个子目录下的所有的类
expression="within(cn.tedu.service.*.*)"
(4)用 .. * 号匹配符
匹配指定包下及其子孙包下的所有的类
此处的 ..*代表匹配指定包下所有的类
expression="within(cn.tedu.service..*)"
b.execution()表达式
语法:execution(返回值类型 包名.类名.方法名(参数类型,参数类型…))
(1)切出指定包下指定类下指定名称指定参数指定返回值的方法
(2)切出指定包下所有的类中的query方法
要求无参,但返回值类型不限。
(3)切出指定包及其子孙包下所有的类中的query方法
要求无参,但返回值类型不限。
(4)切出指定包及其子孙包下所有的类中的query方法
要求参数为int java.langString类型,但返回值类型不限。
(5)切出指定包及其子孙包下所有的类中的query方法
参数数量及类型不限,返回值类型不限。
(6)切出指定包及其子孙包下所有的类中的任意方法
参数数量及类型不限,返回值类型不限。这种写法等价于within表达式的功能。