Aop面向切面

2021/6/27 23:50:39

本文主要是介绍Aop面向切面,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Aop面向切面

1.AOP在spring中的作用

​ 1.横切关注点:跨越应用程序多个模块的方法或者功能,即使与我们的业务逻辑 无关但是我们需要关注的部分就是横切关注点,例如日志,安全。缓存,事务等等;
​ 2.切面(ASPECT):横切关注点,被模块化的特殊对象,也就是一个类;
​ 3.通知(ADVICE):切面必须要完成的工作,也就是类中的一个方法;
​ 4.目标(TARGET):被通知的对象;
​ 5.代理(Proxy):向目标对象应用通知之后创建对象;
​ 6.切入点(PointCut):切面通知执行的“地点”的定义;
​ 7.连接点(JointPoint):与切面匹配的执行点。

2.自定义AOP

2.1真实角色类

package fyjz.com.SpringAOP05;
/*
 *真实角色(房东)
 */
public class Host implements Rent{

	@Override
	public void rent() {
		System.out.println("我要把房子租出去");
		
	}
}

2.2抽象角色接口

package fyjz.com.SpringAOP05;
/*
 * 抽象角色(租房)
 */
public interface Rent {
	void rent();
}

2.3AOP切面类

package fyjz.com.SpringAOP05;
/*
 * AOP切面
 */
public class DiyPointCut {
	public void after(){
		System.out.println("方法后执行。。。");
	}
	
	public void before(){
		System.out.println("方法前执行。。。");
	}
}

2.4XML配置文件

	 <bean id="diy" class="fyjz.com.SpringAOP05.DiyPointCut"/>
	 <bean id="host" class="fyjz.com.SpringAOP05.Host"/>
	 
	 <!--用Spring来管理AOP切面-->
	 <aop:config>
	 	<!--把自定义的切面注入进来-->
	 	<aop:aspect ref="diy">
	 		<!--切入点
		 		expression:要执行的位置
		 		expression="execution(该切入点的方法的修饰词  该切入点的包名.类名 该切入点的方法名(参数类型))":
				如果要写参数列表则是该参数的全称(包名.类名)
	 		-->
	 		<aop:pointcut expression="execution(* fyjz.com.SpringAOP05.Host.*(..))" id="point"/>
	 		<!--通知(在切入点之前执行before  在切入点 之后执行after)-->
	 		<aop:after method="after" pointcut-ref="point"/>
	 		<aop:before method="before" pointcut-ref="point"/>
	 	</aop:aspect>
	 </aop:config>

2.5Test测试类

注意:Aop基于接口生成动态代理,不是基于类生成动态代理的

public class TestDemo01 {
	@Test
	public void test01(){
	ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		Rent r=(Rent)ac.getBean("host");
		r.rent();
	}
}

2.6执行结果

方法前执行。。。
我要把房子租出去
方法后执行。。。

3.注解方式AOP

3.1.XML配置文件

	<!--开启AOP驱动注解-->
	<!--
		  proxy-target-class:false  jdk动态代理
		  proxy-target-class:true  cglib动态代理
	-->
	<aop:aspectj-autoproxy/>
	
	
	<!--让容器管理有标记的对象-->
	<context:component-scan base-package="fyjz.com.SpringAOP07"/>
	

3.2.真实角色类

package fyjz.com.SpringAOP07;

import org.springframework.stereotype.Component;

/*
 * 真实角色
 */
@Component
public class ServiceImpl implements Service{

	
	@Override
	public void add() {
		System.out.println("增加业务");
		
	}

	@Override
	public void delete() {
		
		// TODO Auto-generated method stub
		System.out.println("删除业务");
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		System.out.println("修改业务");
	}

	@Override
	public void select() {
		// TODO Auto-generated method stub
		System.out.println("查询业务");
	}
}

3.3Test测试类

	@Test
	public void test03(){
	ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext3.xml");
		Service s=(Service)ac.getBean("serviceImpl");
		s.delete();

3.4.前置,后置通知

@Component:这是一个标记,容器会识别带有标记的这个类然后去管理由这个类生成的对象

@Aspect:证明这是一个切面,实际上这个切面已经注入到容器中了

前置通知:在切点前执行该方法

后置通知:在切点后执行该方法

package fyjz.com.SpringAOP07;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/*
 * 切面
 */
@Component
@Aspect
public class PointCut {
	//前置通知
	@Before("execution(* fyjz.com.SpringAOP07.ServiceImpl.*(..))")
	public void after(){
		System.out.println("方法前执行");
	}
	
	
	//后置通知
	@After("execution(* fyjz.com.SpringAOP07.ServiceImpl.*(..))")
	public void before(){
		System.out.println("方法后执行");
	}
}

前置后置同时切入,则会执行出以下结果

方法前执行
删除业务
方法后执行

3.5环绕通知

环绕通知:在环绕通知增强中,我们可以给定一个参数代表我们要获取处理切入的点

package fyjz.com.SpringAOP07;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/*
 * 切面
 */
@Component
@Aspect
public class PointCut {

	//环绕通知
	//@Around("execution(* fyjz.com.SpringAOP07.ServiceImpl.delete(..))")
	public void abroub(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("--环绕通知--");
		jp.proceed();//执行切入点的方法
		System.out.println("--环绕后通知--");
	}
}

结果如下:

--环绕通知--
删除业务
--环绕后通知--

3.6前置,后置,环绕通知比较

	//前置通知
	@Before("execution(* fyjz.com.SpringAOP07.ServiceImpl.*(..))")
	public void after(){
		System.out.println("方法前执行");
	}
	
	
	//后置通知
	@After("execution(* fyjz.com.SpringAOP07.ServiceImpl.*(..))")
	public void before(){
		System.out.println("方法后执行");
	}
	
	//环绕通知
	
	@Around("execution(* fyjz.com.SpringAOP07.ServiceImpl.delete(..))")
	public void abroub(ProceedingJoinPoint jp) throws Throwable{
		System.out.println("--环绕通知--");
		jp.proceed();//执行切入点的方法
		System.out.println("--环绕后通知--");
	}

我们让后置,前置,以及环绕通知同时切入 ,则会发生一下结果:

--环绕通知--
方法前执行
删除业务
--环绕后通知--
方法后执行

可以看出:后置通知总是最后执行的

3.7异常捕获

切入点发生异常时,被@AfterThrowing捕获

	//异常捕获
	@AfterThrowing("execution(* fyjz.com.SpringAOP07.ServiceImpl.delete(..))")
	public void afterthrowing(){//不能带参数
		System.out.println("发生异常了");
	}

如果我们修改一下delete方法让其出错,那么该方法会捕获到异常

如:

	@Override
	public void delete() {
		String s="";
		char c=s.charAt(2);
		// TODO Auto-generated method stub
		System.out.println("删除业务");
	}

结果如下:

发生异常了


这篇关于Aop面向切面的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程