在Spring AOP编程中:
分离了重复代码:关注点
关注点代码:产生类即切面类
一、使用 AspectJ实现 AOP(注解方式):
- 导包
spring-aop
spring-core
aspectjrt
aspectjweaver
aopalliance - 配置文件(开启代理模式)
开启注解扫描
<context:component-scan base-package="com.asd"></context:component-scan>
开启代理模式
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 切面类
@Component
@Aspect:说明这是一个切面类
@Before:业务代码之前执行
@After:业务代码之后执行,无论是否出现异常都执行
@AfterReturning:业务代码后执行,若出现异常不执行
@AfterThrowing:业务代码后,出现异常执行(即@AfterReturning与@AfterThrowing 两者不会同时存在)
@Around:环绕业务代码,有参数joinPoint:joinPoint.proceed();方法proceed()相当于目标对象业务代码中的save(); - 切入点表达式(exection( * * . *(. .)))
exection( * * . *(. .)) 即
exection( 返回类型 类的完全限定名. 方法名(参数))(返回类型前的修饰符如public可写可不写)
实现接口的类,Spring默认使用JDK代理;未实现接口的类,Spring默认使用Cglib代理
@Before("execution(public void com.asd.spring.UserDao.save())")
@After("execution(public void com.asd.spring.UserDao.save())")
二、使用 AspectJ实现 AOP(XML 方式):
① 接口实现类(UserDao.java)、未实现类(OrderDao.java)和切面类(MyAop.java)都不需要用注解;② 不用注解的方式则xml中不需要开启注解扫描和开启代理模式,需要在 xml文件中生成对应的 bean对象:xml 文件中有生成UserDao、OrderDao、切面类MyAop对象;可以在< aop:before>标签中用 pointcut属性单独书写每一个切入点表达式;也可以在< aop:pointcut>用 expression属性统一书写切入点表达式, express属性中可以用 “||”和“or”来写多个表达式,再在< aop:before>标签中用 pointcut-ref属性引用它;
// eg:
<aop:config>
<!-- 切面类-->
<bean id="aop" class="com.asd.spring.MyAop"></bean>
<!-- 切入点 -->
<aop:pointcut id="pt" expression="execution(* *.*.*(..))"/>
<aop:aspect ref="aop">
<aop:before method="beginTrans" pointcut-ref="pt"/>
<aop:after method="commitTrans" pointcut-ref="pt"/>
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<aop:after-throwing method="afterThrow" pointcut-ref="pt"/>
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
eg: 1. 使用 AspectJ实现 AOP(注解方式)
1.1 IUserDao.java
public interface IUserDao{
public void save() throws Exception;
public void update() throws Exception;
}
1.2 UserDao.java
(此目标对象实现接口)
@Component("userDao")
public class UserDao implements IUserDao{
public void save() throws Exception{
System.out.println("----数据已保存----");
// int i=1/0;
}
public void update() throws Exception{
System.out.println("----数据已修改----");
}
}
1.2(1) OrderDao.java
(新增一个OrderDao,不实现接口)
@Component("orderDao")
public class OrderDao{
public void update() throws Exception{
System.out.println("----修改订单----");
}
}
1.3 MyAop.java
(① 目标对象提取后形成的单独类:@Aspect注解表示这是一个切面类;@Before(“execution(public void com.asd.spring.UserDao.save())”) 是切入点表达式;② 若在UserDao.java中出现异常,此时@AfterReturning不执行;③ 为避免重复书写切入点表达式,可以用@PointCut注解写一个切入点方法,无需实现;后面注解中只需要引用方法即可,不需要再多次书写切入点表达式;)
@Component
@Aspect
public class MyAop{
//@PointCut("execution(public void com.asd.spring.UserDao.save())")
@PointCut("execution(* *.*())")
public void pointCut(){
}
//@Before("execution(public void com.asd.spring.UserDao.save())")
@Before("pointCut()")
public void beginTrans(){
System.out.println("开始事务");
}
//@After("execution(public void com.asd.spring.UserDao.save())")
@After("pointCut()")
public void commitTrans(){
System.out.println("提交事务");
}
//@AfterReturning("execution(public void com.asd.spring.UserDao.save())")
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("afterReturning");
}
//@AfterThrowing("execution(public void com.asd.spring.UserDao.save())")
@AfterThrowing("pointCut()")
public void afterThrow(){
System.out.println("afterThrow");
}
//@Around("execution(public void com.asd.spring.UserDao.save())")
@Around("pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("begin");
joinPoint.proceed();
System.out.println("end");
}
}
1.4 bean.xml
(xml文件中有: xmlns:context、 xmlns:aop、xmlns:tx即context、aop、tx命名空间, )
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.asd"></context:component-scan>
<!-- 开启代理模式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
Test.java
public class Test{
public static void main(String[] args) {
ApplicationContext applicationContext=new ApplicationContext("bean.xml");
IUserDao userDao=(IUserDao)applicationContext.getBean("userDao");
System.out.println(userDao.getClass());//userDao对象(即实现接口的目标对象)类型
try{
userDao.save();
userDao.update();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("-------------");
OrderDao orderDao=(OrderDao)applicationContext.getBean("orderDao");
System.out.println(orderDao.getClass());//orderDao对象(即没有实现接口的目标对象)类型
try{
orderDao.update();
}catch(Exception e){
e.printStackTrace();
}
}
}
① MyAop.java切面类中只有 @Before、@After 注解时,运行结果:
② MyAop.java切面类中增加 @AfterReturning 注解后且无异常,运行结果: / 出现异常运行结果:
③ MyAop.java切面类中增加 @AfterThrowing 注解后且出现异常,运行结果:
④ MyAop.java切面类中增加 @Around 注解后运行结果:
⑤ 增加 OrderDao.java 类后,切面类 MyAop.java中切入点表达式方法只限定OrderDao(即未改为全部即 * )注解后运行结果:(没有执行切入点代码)
⑤ 增加 OrderDao.java 类、且在UserDao.java类中添加 update() 方法,切面类 MyAop.java中切入点表达式方法为全部类和方法(即 * )后运行结果:(有执行切入点代码)
⑥ 输出两个对象userDao对象(实现接口)、orderDao对象(没实现接口)运行结果:
userDao对象类型:class com.sun.proxy.$Proxy12
orderDao对象类型:class com.asd.spring.OrderDao $ $EnhancerBySpringCGLIB $ $ 87c00f1f
【 可看出实现接口的类Spring默认使用JDK代理,未实现接口的类Spring默认使用Cglib代理 】
二、使用 AspectJ实现 AOP(XML 方式):
(① 接口实现类(UserDao.java)、未实现类(OrderDao.java)和切面类(MyAop.java)都不需要用注解;② 不用注解的方式则xml中不需要开启注解扫描和开启代理模式,需要在 xml文件中生成对应的 bean对象:xml 文件中有生成UserDao、OrderDao、切面类MyAop对象;可以在< aop:before>标签中用 pointcut属性单独书写每一个切入点表达式;也可以在< aop:pointcut>用 expression属性统一书写切入点表达式, express属性中可以用 “||”和“or”来写多个表达式,再在< aop:before>标签中用 pointcut-ref属性引用它;)
2.1 IUserDao.java
public interface IUserDao{
public void save() throws Exception;
public void update() throws Exception;
}
2.2 UserDao.java
public class UserDao implements IUserDao{
public void save() throws Exception{
System.out.println("----数据已保存----");
// int i=1/0;
}
}
2.2(1) OrderDao.java
public class OrderDao{
public void update() throws Exception{
System.out.println("----修改订单----");
}
}
2.3 MyAop.java
public class MyAop{
public void beginTrans(){
System.out.println("开始事务");
}
public void commitTrans(){
System.out.println("提交事务");
}
public void afterReturning(){
System.out.println("afterReturning");
}
public void afterThrow(){
System.out.println("afterThrow");
}
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("begin");
joinPoint.proceed();
System.out.println("end");
}
}
2.4 bean.xml
(xml 文件中有生成UserDao、OrderDao、切面类MyAop对象,可以在< aop:before>标签中用 pointcut属性单独书写每一个切入点表达式;也可以在< aop:pointcut>用 expression属性统一书写切入点表达式, express属性中可以用 “||”和“or”来写多个表达式,再在< aop:before>标签中用 pointcut-ref属性引用它;)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 容器中创建UserDao、OrderDao对象 -->
<bean id="userDao" class="com.asd.spring.UserDao"></bean>
<bean id="orderDao" class="com.asd.spring.OrderDao"></bean>
<!-- 容器中创建切面类对象 -->
<bean id="aop" class="com.asd.spring.MyAop"></bean>
<!-- 切入点 -->
<aop:config>
//<aop:pointcut id="pt" expression="execution(* com.asd.UserDao.save(..))"/>//统一写切入点表达式,再在下面pointcut-ref引用其id
//<aop:pointcut id="pt" expression="execution(* com.asd.UserDao.save(..)) ||execution(* com.asd.UserDao.update(..))"/>//用“||”和“or”都可以
<aop:pointcut id="pt" expression="execution(* *.*.*(..))"/>
<aop:aspect ref="aop">
//<aop:before method="beginTrans" pointcut="execution(* com.asd.UserDao.save(..))"/>//分开写
<aop:before method="beginTrans" pointcut-ref="pt"/>
<aop:after method="commitTrans" pointcut-ref="pt"/>
<aop:after-returning method="afterReturning" pointcut-ref="pt"/>
<aop:after-throwing method="afterThrow" pointcut-ref="pt"/>
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
Test.java
在这里插入代码片