Spring--AOP环境搭建及五种通知

1.增强一个类的三种方式

继承

​ 派生子类,重写方法

​ 增强的对象不可以变,增强的功能可以变
装饰者模式

​ FileOutStream

​ BufferedOutputStream

​ 增强的对象可以变,增强的功能不变

/**
*@version 2020年7月22日下午3:19:34
*类说明:装饰者模式
*/
//面条
class Noodles {
	public String getNoodles() {
		return "noodles";
	}
}
//加盐
class SaltNoodles extends Noodles{
	Noodles noodles;
	public SaltNoodles(Noodles noodles) {
		super();
		this.noodles = noodles;
	}	
	public String getNoodles() {
		return "salt" + noodles.getNoodles();
	}
}
//加辣椒
class PepperNoodles extends Noodles{
	Noodles noodles;
	public PepperNoodles(Noodles noodles) {
		super();
		this.noodles = noodles;
	}
	public String getNoodles() {
		return "pepper" + noodles.getNoodles();
	}
}

public class NoodlesTest{
	public static void main(String[] args) {
		Noodles noodles = new Noodles();
		System.out.println(noodles.getNoodles());
        
		SaltNoodles saltNoodles = new SaltNoodles(noodles);
		System.out.println(saltNoodles.getNoodles());
		
		PepperNoodles pepperNoodles = new PepperNoodles(saltNoodles);
		System.out.println(pepperNoodles.getNoodles());
	}
}

动态代理

​ 增强的对象和增强的功能都可以变,是一种最灵活的增强方式

​ MyBatisMapper动态代理,AOP底层

​ 接口:

public interface SomeService {
	void doSome();
	String doOther();
	void test();
}

​ 实现类:

public class SomeServiceImp implements SomeService{
	@Override
	public void doSome() {
		System.out.println("doSome");		
	}
	@Override
	public String doOther() {
		System.out.println("doOther");
		return "doOther";
	}
	@Override
	public void test() {
		System.out.println("test");		
	}
}

动态代理测试类:

public class MyProxy {
	/*
	 * 	动态代理有两种实现:
	 * Proxy:JDK内置,要求目标类,必须有接口
	 * cglib:第三方jar包,有没有接口都可以增强
	 */
	public static void main(String[] args) {
		//目标对象
		SomeService someService= new SomeServiceImp();
		//返回值是一个代理对象:目标对象增强以后的对象
		/*
		 * ClassLoader loader:类加载器
		 * Class<?> interfaces:目标类的所有接口
		 * InvocationHandler h : 接口,需要用这个接口的实现类完成对目标类的增强
		 */
		SomeService obj = (SomeService) Proxy.newProxyInstance(someService.getClass().getClassLoader(), someService.getClass().getInterfaces(), 			
				new InvocationHandler() {
					/*Object proxy: 代理对象
					 * Method method:目标方法
					 * Object[] args : 目标方法的参数
					 */
					@Override
					public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
						//切面--织入--前置通知
						System.out.println("前置增强");
						//调用目标方法
						Object resoult = arg1.invoke(someService, arg2);
						//切面--织入--后置通知
						System.out.println("后置增强");
						return resoult;
					}
				});
		obj.doSome();
		System.out.println("---------");
		obj.doOther();
		System.out.println("---------");
		obj.test();
	}
}

2. Spring搭建AOP环境

AOP是一种编程思想,很多框架都实现了AOP

​ Spring自己实现了AOP,使用麻烦:

​ IoC的基本jar+aop联盟包(官方组织,定义规范,aop接口)+aop.jar

​ AspectJ框架也实现,Spring官方也推荐使用AspectJ

​ IoC的基本jar+aopalliance.jar联盟包(官方组织,定义规范,aop接口)+aop.jar+aspectJ.jar+spring对apsectj整合包

在这里插入图片描述

3.五种通知-注解方式

添加约束头

<?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.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    <!-- bean definitions here -->
    <!-- 目标类对象 -->
	<bean id="someServie" class="com.woniu.service.SomeServiceImp" />	
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service.MyAspect" />
	<aop:aspectj-autoproxy />	
</beans>

下面注解方式和配置方式都用到的接口和实现类及测试类

接口:

public interface SomeService {
	void doSome();
	String doOther();
	void test();
}

实现类:

public class SomeServiceImp implements SomeService{
	@Override
	public void doSome() {
		System.out.println("doSome");		
	}
	@Override
	public String doOther() {
		System.out.println("doOther");
		return "doOther";
	}
	@Override
	public void test() {
		System.out.println("test");		
	}
}

测试类:

public class SomeServiceImpTest {
	@Test
	public void testSomeService01() {
		String path="com/woniu/service/applicationContext.xml";
		//加载配置文件创建spring容器
		ApplicationContext ac = new ClassPathXmlApplicationContext(path);
		//获取Bean
		SomeService someService = (SomeService) ac.getBean("someServie");
		someService.doSome();
		System.out.println("--------");
		System.out.println(someService.doOther());
		System.out.println("--------");
		someService.test();
	}
}

前置通知

//定义切面类:将交叉业务方法,定义在切面类中
//这个注解告诉框架,当前类是切面类
@Aspect
public class MyAspect {	
	//前置通知:在目标方法执行之前,织入当前的交叉业务
	//切入点表达式:满足什么条件的方法,会织入
	@Before("execution(* *..SomeService.do*(..))")
	public void before() {
		System.out.println("before");
	}
	//所有的织入的方法都可以添加一个参数JoinPoint:切入点
	@Before("execution(* *..SomeService.do*(..))")
	public void before(JoinPoint jp) {
		System.out.println("before,jp="+jp);
	}
}

后置通知

//定义切面类:将交叉业务方法,定义在切面类中
//这个注解告诉框架,当前类是切面类
@Aspect
public class MyAspect {	
	//后置通知:在目标方法执行之后,织入当前的交叉业务
	//切入点表达式:满足什么条件的方法,会织入
	@AfterReturning("execution(* *..SomeService.do*(..))")
	public void afterReturning() {
		System.out.println("afterReturning");
	}
	//后置通知可以获取目标方法的返回值,但不能修改
	@AfterReturning(value="execution(* *..SomeService.doOther(..))",returning="obj")
	public void afterReturning(Object obj) {
		System.out.println("afterReturning");
		System.out.println("后置通知获取的返回值:" + obj.toString().toUpperCase());
	} 
}

环绕通知

//定义切面类:将交叉业务方法,定义在切面类中
//这个注解告诉框架,当前类是切面类
@Aspect
public class MyAspect {
	//环绕通知:功能最强,可以替换其他四种通知的所有功能
	//可以修改方法的返回值
	@Around("execution(* *..SomeService.doOther(..))")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕前");
		//通过ProceedingJoinPoint参数对象调用目标方法
		Object object = pjp.proceed();
		System.out.println("环绕后");
		return object.toString().toUpperCase();
	}
}

异常通知

//定义切面类:将交叉业务方法,定义在切面类中
//这个注解告诉框架,当前类是切面类
@Aspect
public class MyAspect {	
	//异常通知:目标方法发送异常以后执行
	//切入点表达式:满足什么条件的方法,会织入
	@AfterThrowing("execution(* *..SomeService.test(..))")
	public void afterThrowing() {
		System.out.println("异常通知");
	}	
	@AfterThrowing(value="execution(* *..SomeService.test(..))",throwing = "ex")
	public void afterThrowing(Exception ex) {
		System.out.println("异常通知Exception:"+ex);
	}
	@AfterThrowing(value="execution(* *..SomeService.test(..))",throwing = "ex")
	public void afterThrowing(ArithmeticException ex) {
		System.out.println("异常通知ArithmeticException:"+ex);
	}
}

异常通知的test()方法手动抛了个异常来测试

	@Override
	public void test() {
		System.out.println("test");	
		if(true) {
			throw new ArithmeticException("自定义异常");
		}
	}

最终通知

//定义切面类:将交叉业务方法,定义在切面类中
//这个注解告诉框架,当前类是切面类
@Aspect
public class MyAspect {
	//最终通知:有没有异常多会执行
	@After("execution(* *..SomeService.do*(..))")
	public void after() {
		System.out.println("最终通知");
	}
}

4.五种通知-配置applicationContext.xml方式

前置通知

//切面类
public class MyAspect {
	public void before() {
		System.out.println("before");
	}
	public void before(JoinPoint jp) {
		System.out.println("before,jp="+jp);
	}
}
<?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.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> 
    <!-- bean definitions here -->
    <!-- 目标类对象 -->
	<bean id="someServie" class="com.woniu.service06.SomeServiceImp" />
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service06.MyAspect" />	
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..SomeService.doSome(..))" id="doSomePointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.doOther(..))" id="doOtherPointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.test(..))" id="testPointcut"/>	
		<!-- 配置切面织入 -->
		<aop:aspect ref="myAspect">
			<aop:before method="before"  pointcut="execution(* *..SomeService.doSome(..))"/>
			<aop:before method="before"  pointcut-ref="doOtherPointcut"/>
			<aop:before method="before"  pointcut-ref="testPointcut"/>
		</aop:aspect>
	</aop:config>	
</beans>

后置通知

//切面类
public class MyAspect{
	public void afterReturning() {
		System.out.println("afterReturning");
	}
	public void afterReturning(Object obj) {
		System.out.println("afterReturning");
		System.out.println("后置通知获取的返回值:" + obj.toString().toUpperCase());
	} 
}
<!-- 目标类对象 -->
	<bean id="someServie" class="com.woniu.service07.SomeServiceImp" />	
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service07.MyAspect" />
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..SomeService.doSome(..))" id="doSomePointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.doOther(..))" id="doOtherPointcut" />
		<aop:pointcut expression="execution(* *..SomeService.test(..))" id="testPointcut"/>
		<!-- 配置切面织入 -->
		<aop:aspect ref="myAspect" >
			<aop:after method="afterReturning"  pointcut="execution(* *..SomeService.doSome(..))"/>
			<aop:after-returning method="afterReturning(java.lang.Object)"  pointcut-ref="doOtherPointcut" returning="obj"/>
		</aop:aspect>
	</aop:config>

环绕通知

//切面类
public class MyAspect {
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("环绕前");
		//通过ProceedingJoinPoint参数对象调用目标方法
		Object object = pjp.proceed();
		System.out.println("环绕后");
		return object.toString().toUpperCase();
	}	
}
<bean id="someServie" class="com.woniu.service08.SomeServiceImp" />	
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service08.MyAspect" />
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..SomeService.doSome(..))" id="doSomePointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.doOther(..))" id="doOtherPointcut" />
		<aop:pointcut expression="execution(* *..SomeService.test(..))" id="testPointcut"/>
		<!-- 配置切面织入 -->
		<aop:aspect ref="myAspect" >
			<aop:around method="around"  pointcut-ref="doOtherPointcut" />
		</aop:aspect>
	</aop:config>

异常通知

//切面类
public class MyAspect {
	public void afterThrowing() {
		System.out.println("异常通知");
	}	
	public void afterThrowing(Exception ex) {
		System.out.println("异常通知Exception:"+ex);
	}
	public void afterThrowing(ArithmeticException ex) {
		System.out.println("异常通知ArithmeticException:"+ex);
	}
}
<!-- 目标类对象 -->
	<bean id="someServie" class="com.woniu.service09.SomeServiceImp" />	
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service09.MyAspect" />	
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..SomeService.doSome(..))" id="doSomePointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.doOther(..))" id="doOtherPointcut" />
		<aop:pointcut expression="execution(* *..SomeService.test(..))" id="testPointcut"/>
		<!-- 配置切面织入 -->
		<aop:aspect ref="myAspect" >
			<!-- <aop:after-throwing  method="afterThrowing"  pointcut-ref="doSomePointcut"/>
			<aop:after-throwing  method="afterThrowing"  pointcut-ref="doOtherPointcut"/> -->
			<aop:after-throwing  method="afterThrowing(java.lang.Exception)" throwing="ex" pointcut-ref="testPointcut" />			
		</aop:aspect>
	</aop:config>

最终通知

//切面类
public class MyAspect {
	public void after() {
		System.out.println("最终通知");
	}
}
<!-- 目标类对象 -->
	<bean id="someServie" class="com.woniu.service10.SomeServiceImp" />	
	<!-- 切面类对象 -->
	<bean id="myAspect" class="com.woniu.service10.MyAspect" />	
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..SomeService.doSome(..))" id="doSomePointcut"/>
		<aop:pointcut expression="execution(* *..SomeService.doOther(..))" id="doOtherPointcut" />
		<aop:pointcut expression="execution(* *..SomeService.test(..))" id="testPointcut"/>
		<!-- 配置切面织入 -->
		<aop:aspect ref="myAspect" >
			<aop:after method="after" pointcut-ref="doSomePointcut"/>		
		</aop:aspect>
	</aop:config>

类对象 -->

aop:config

<aop:pointcut expression=“execution(* …SomeService.doSome(…))" id=“doSomePointcut”/>
<aop:pointcut expression="execution(
…SomeService.doOther(…))" id=“doOtherPointcut” />
<aop:pointcut expression="execution(
*…SomeService.test(…))” id=“testPointcut”/>

<aop:aspect ref=“myAspect” >
<aop:after method=“after” pointcut-ref=“doSomePointcut”/>
</aop:aspect>
</aop:config>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值