Spring系列三面向切面

Spring面向切面

面向切面编程:

即定义一个通用的功能,但是可以通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类。

相关术语:

通知(Advice):定义切面是做什么以及什么时候执行,Spring定义了5中类型的通知。

前置通知:在目标方法被调用前执行通知的功能

后置通知:在目标方法完成之后,调用通知

返回通知:在目标方法成功执行之后调用通知

异常通知:在目标方法抛出异常后调用通知

环绕通知:在目标方法被执行之前,之后,执行自定义的通知。

连接点(Join point):即在何处应用通知,即在应用执行过程中能够插入切面的一个点,这个点可以是调用方法时,抛出异常时,修改一个字段的时候。

切点(Point Cut):何处,匹配通知所要织入的一个或者多个连接点。

切面(Aspect):通知和切点的结合,定义一个在何时,何地,执行什么功能。

引入(Introduction):允许我们向现有的类添加新的方法或属性。

织入(Weaving):把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。

 

Spring对AOP的支持:

不是所有的AOP框架是相同的,Spring提供了4种类型的AOP支持:

⑴基于代理的经典Spring AOP

⑵纯POJO切面

⑶@AspectJ注解驱动的切面

⑷注入式AspectJ切面

Spring提供了更方便的面向切面编程方式,即引入了简单的声明式AOP和基于注解的AOP。

Spring通知使用Java编写,可以使用注解或者Spring配置文件采用XML来编写。

Spring在运行时通知对象:在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中,代理类封装目标类,并拦截被通知方法的调用,把调用转发给真正的目标bean,当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。

Spring只支持方法级别的连接点:因为Spring基于动态代理,所以Spring只支持方法连接点。

切点的编写:

execution(* com.dong.test.method(..))

在方法执行时触发, *表示返回任意类型,com.dong.test方法所属的类,method具体方法,(..)使用任意参数。

使用withIn()指示器来限制匹配

execution(* com.dong.test.method(..)) && within(com.dong.test2.*)),也可以使用||,!来进行操作,因为&在xml中有特殊的含义,因此可以使用and代替&&,or代替||,not代替!

在切点中选择bean

execution( * com.dong.test.method(..) ) and bean('beanId‘)

1.使用注解创建切面:

AspectJ5引入使用注解来创建切面。

@Aspect 定义切面

@Before 前置通知

@After后置通知

@Around 环绕通知

@AfterReturning 返回通知

@AfterThrowing 异常通知

@Pointcut 定义切点

@EnableAspectJAutoProxy 启动自动代理功能,否则被注解的类不会被当做一个 切面,注解不会解析,

处理通知中的参数:

execution ( * com.dong.test.method(int)) && args(argsname)

返回任意类型,方法所属的类型,方法,接受int类型的参数,指定参数,将参数传递给目标方法。

具体案例:

package AnnotationTypeBean;


import org.springframework.stereotype.Component;

@Component
public class EatFood {
	public void eatFoods() {
		System.out.println("要吃饭啦.......");
	}
}

package AnnotationTypeBean;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class Prepared {
	@Pointcut("execution(** AnnotationTypeBean.EatFood.eatFoods(..) )")
	public void func() {}
	
	@Before("func()")
	public void  preparedEatFood() {
		System.out.println("先洗手,在吃饭");
	}
	@After("func()")
	public void finishEat() {
		System.out.println("吃完饭收拾桌子");
	}
}

package AnnotationTypeBean;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//创建环绕通知
@Aspect
@Component
public class Prepared2 {
	
	@Pointcut("execution(** AnnotationTypeBean.EatFood.eatFoods(..) )")
	public void func() {}
	
	@Around("func()")
	public void test(ProceedingJoinPoint pjp) throws Throwable {
		try {
			System.out.println("先洗手,在吃饭...");
			pjp.proceed();
			System.out.println("吃完饭收拾桌子.....");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("不可以吃饭....");
		}
	}	
}

package AnnotationTypeBean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
 * 运行结果:
 * 先洗手,在吃饭
 * 先洗手,在吃饭...
 * 要吃饭啦.......
 * 吃完饭收拾桌子.....
 * 吃完饭收拾桌子
 * @author liumin
 */
@Configuration
@ComponentScan("AnnotationTypeBean")
@EnableAspectJAutoProxy
public class Start {
	public static void main(String args[]) {
			ApplicationContext context =new AnnotationConfigApplicationContext(AnnotationTypeBean.Start.class);
			EatFood eat = (EatFood) context.getBean("eatFood");
			eat.eatFoods();
			
	}
}

2.在XML中声明切面:

Spring的aop命名空间,提供了多个元素用来在XML中声明切面

<aop:advisor> 定义AOP通知器

<aop:after> 定义后置通知

<aop:before>定义前置通知

<aop:around>定义环绕通知

<aop:after-returning>定义返回通知

<aop:after-throwing>定义异常通知

<aop:aspect>定义一个切面

<aop:pointcut>定义一个切点

具体代码:xx.xml文件

<?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-4.3.xsd">

<bean id="eatfood" class="com.dong.XmlTypeAop.EatFood"></bean>
<bean id="prepared" class="com.dong.XmlTypeAop.Prepared"></bean>
<bean id="prepared2" class="com.dong.XmlTypeAop.Prepared2"></bean>

<aop:config>
	<aop:aspect ref="prepared2">
			<aop:pointcut id="eat" expression="execution (** com.dong.XmlTypeAop.EatFood.eatFoods(..) )"  />
			<aop:around pointcut-ref="eat" method="test"/>
	</aop:aspect>
</aop:config>

</beans>

<!--
    后置通知
<aop:after pointcut ="execution (** com.dong.XmlTypeAop.EatFood.eatFoods(..))" method="preparedEatFood"/>
 !-->

代码:和上一个例子相似,去掉注解

package com.dong.XmlTypeAop;

public class EatFood {
	public void eatFoods() {
		System.out.println("要吃饭啦.......");
	}
}

package com.dong.XmlTypeAop;

public class Prepared {
	public void  preparedEatFood() {
		System.out.println("先洗手,在吃饭");
	}
	public void finishEat() {
		System.out.println("吃完饭收拾桌子.....");
	}
}

package com.dong.XmlTypeAop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;

public class Prepared2 {	
	
	public void test(ProceedingJoinPoint pjp) throws Throwable {
		try {
			System.out.println("先洗手,在吃饭...");
			pjp.proceed();
			System.out.println("吃完饭收拾桌子.....");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("不可以吃饭....");
		}
	}
}

package com.dong.XmlTypeAop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * 运行结果:
 * 先洗手,在吃饭...
 * 要吃饭啦.......
 * 吃完饭收拾桌子.....
 * @author liuD
 *
 */
public class Start {
	public static void main(String args[]) {
		ApplicationContext context = new ClassPathXmlApplicationContext("Application.xml");
		EatFood eatfood = (EatFood) context.getBean("eatfood");
		eatfood.eatFoods();
	}
}

部分内容参考《Spring实战》(第四版)

 

全部评论

相关推荐

不亏是提前批,神仙打架,鼠鼠不配了
站队站对牛:现在92都报工艺岗了
投递韶音科技等公司7个岗位
点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务