Spring(2)之 (2.2 使用 AspectJ实现 AOP)

在Spring AOP编程中:

分离了重复代码:关注点
关注点代码:产生类即切面类
 

一、使用 AspectJ实现 AOP(注解方式):

  1. 导包
    spring-aop
    spring-core
    aspectjrt
    aspectjweaver
    aopalliance
  2. 配置文件(开启代理模式)
    开启注解扫描
<context:component-scan base-package="com.asd"></context:component-scan>

开启代理模式

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
  1. 切面类
    @Component
    @Aspect:说明这是一个切面类
    @Before:业务代码之前执行
    @After:业务代码之后执行,无论是否出现异常都执行
    @AfterReturning:业务代码后执行,若出现异常不执行
    @AfterThrowing:业务代码后,出现异常执行(即@AfterReturning与@AfterThrowing 两者不会同时存在)
    @Around:环绕业务代码,有参数joinPoint:joinPoint.proceed();方法proceed()相当于目标对象业务代码中的save();
  2. 切入点表达式(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

在这里插入代码片

猜你喜欢

转载自blog.csdn.net/qq_41029923/article/details/84250237