1.AOP及其相关概念
1)AOP 面向切面(方面)编程
主要解决共通处理问题.可以将共通处理部分单独用一个组件封装起来,然后利用SpringAOP机制作用到某一批目标对象上面.从而降低共通处理对象和目标对象之间关联.
AOP与OOP关系,OOP面向对象编程,侧重于对象的封装;AOP面向切面编程是以OOP为基础,侧重于对共通处理的操作.改善程序结构,提高灵活性.
2)切面(方面)Aspect
指的是共通处理部分的代码.也称为关注点的实现.
3)连接点Joinpoint
指的是作用在目标对象上的位置.例如方法调用,异常发生后等
4)切入点Pointcut
指的是连接点的集合,对应一个切入点表达式.
5)目标对象Target Object
指的是使用切面功能的对象.需要在Spring容器中.
6)通知 Advice
指的是连接点作用的时机.例如方法调用前,方法调用后执行切面功能等.
7)动态代理AutoProxy
采用AOP之后,Spring会为每一个目标对象创建一个代理对象,该代理对象相当于切面和目标对象功能的结合体.
Spring采用两种方式:
a.JDK Proxy方式
适用于目标对象有接口.
b.CGLIB方式
适用于目标对象没有接口.
2.AOP使用示例
UserDAO.java:
1 2 3 4 5 6 7 |
package com.weishuzhai.target; public interface UserDAO { public void save(); public void findByEmail(String email); } |
实现类UserDAOImpl.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package com.weishuzhai.target; public class JDBCUserDAOImpl implements UserDAO { public void findByEmail(String email) { System.out.println("采用JDBC技术保存用户信息"); } public void save() { System.out.println("采用JDBC技术查询用户信息"); } } |
UserService.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.weishuzhai.user; import org.junit.Test; import com.weishuzhai.target.UserDAO; public class UserService { public UserDAO userDao; public void setUserDao(UserDAO userDao) { this.userDao = userDao; } /** * 注册业务方法 * */ public void regist() { // System.out.println("-- 欢迎使用该功能 --"); System.out.println("数据保存成功!谢谢使用!"); userDao.save(); } /** * 登录业务方法 * */ public void login() { System.out.println("登录成功,谢谢使用!"); userDao.findByEmail("Tom"); } } |
1)示例步骤
a.引入jar包
aspectjweaver.jar
aspectjrt.jar
cglib-nodep-2.1_3.jar
commons-logging.jar
spring.jar
b.寻找关注点,采用切面组件封装.
切面组件MyAspect.java:
1 2 3 4 5 6 7 8 9 10 11 |
package com.weishuzhai.aspect; public class MyAspect { public void myAspectBefore() { System.out.println("-- 欢迎使用该功能 --"); } public void myAspectAfter() { System.out.println("-- 功能使用结束!谢谢使用 --"); } } |
c.在spring配置中添加AOP配置
添加aop命名空间
指定切面
1 |
<aop:aspect /> |
定义切入点
1 |
<aop:pointcut /> |
指定切入点采用哪种类型的通知
1 |
<aop:before /> |
spring配置文件applicationContext.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
< ?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-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" default-lazy-init="true"> <bean id="userDAO" class="com.weishuzhai.target.JDBCUserDAOImpl"/> <bean id="userService" class="com.weishuzhai.user.UserService"> <property name="userDao" ref="userDAO"></property> </bean> <!-- AOP配置 --> <bean id="myAspect" class="com.weishuzhai.aspect.MyAspect"/> <aop:config> <!-- 将myAspect Bean组件指定为切面组件 --> <aop:aspect id="aspectEx" ref="myAspect"> <!-- 切入点,匹配UserService类中的所有方法 --> <aop:pointcut id="servicePointcut" expression="execution(* com.weishuzhai.user.UserService.*(..))"></aop:pointcut> <!-- 定义前置通知.指定切面组件中的myAspectbefore方法,在切入点之前调用 --> <aop:before pointcut-ref="servicePointcut" method="myAspectBefore"></aop:before> <!-- 定义最终通知,指定切面组件中的myAspectAfter方法,在切入点之后调用 --> <aop:after pointcut-ref="servicePointcut" method="myAspectAfter"></aop:after> </aop:aspect> </aop:config> </beans> |
d.测试执行TestUserService.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.weishuzhai.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.weishuzhai.user.UserService; public class TestUserService { @Test public void test() { ApplicationContext ac = new ClassPathXmlApplicationContext( "applicationContext.xml"); UserService service = (UserService) ac.getBean("userService"); service.regist(); service.login(); } } |
运行结果:
3.通知类型
1)前置通知
1 |
<aop:before /> |
目标对象方法调用前执行.
2)后置通知
1 |
<aop:after -returning/> |
目标对象方法成功调用之后执行.
3)最终通知
1 |
<aop:after /> |
目标对象方法调用之后执行,不论是成功还是失败.
4)环绕通知
1 |
<aop:around /> |
目标对象方法调用之前和之后执行.
5)异常通知
1 |
<aop:after -throwing/> |
目标对象方法调用出现异常后执行.
try{
前置通知
环绕通知1
目标对象方法
环绕通知1
后置通知
}catch(){
异常通知
}finally{
最终通知
}
4.切入点表达式
*1)方法限定execution
示例1:任意公共方法的执行
execution (public * *(..))
示例2:任何一个名字以“set”开始的方法的执行
execution (* set*(..))
示例3:AccountService中定义的任意方法的执行
execution (* service.AccountService.*(..))
示例4:在service包中定义的任意方法的执行
execution (* service.*.*(..))
示例5:在service包或其子包中定义的任意方法的执行
execution (* service..*.*(..))
*2)类型限定within
示例1:AccountService中定义的任意方法的执行
within (service.AccountService)
示例2:在service包中定义的任意类型的任意方法
within (service.*)
示例3:在service包或其子包中定义的任意类型的任意方法
within (service..*)
*3)Bean对象名限定bean
示例:匹配所有的id或name名字以Service结束的组件
bean(*Service)
4)特定类型限定this或target
this指的是限定特定的代理类型
target指的是限定特定的目标对象类型
示例1:实现了AccountService的代理对象
this (service.AccountService)
示例2:实现了AccountService的目标对象
target (service.AccountService)
5)方法参数限定args
示例:匹配方法有一个String参数的
args (java.lang.String)
—————————–