标签:最简 运行时 pat null wing 代理 pojo ida beans
1. Web MVC发展史历程
2.Spring概要
3.Spring-依赖注入概要(IOC)
4.属性注入的三种实现方式
5.Spring-IoC XML装配
6.Spring-XML设置Bean的值
7.Spring-IoC 注解(1)
8.Spring-IoC 注解(2)
9.Spring-AOP切面编程(1)
10.Spring-AOP切面编程(2)
11.Spring-AOP切面编程(3)
Spring 使用了和AspectJ 一样的注解并使用AspectJ来做切入点解析和匹配。但是,AOP在运行时仍旧是纯的Spring AOP,并不依赖于AspectJ的编译器或者织入器(weaver)(编译器与织入器暂时不要管)
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.wener.example.aop.aspect"/>
<!-- 有了这个Spring就能够自动扫描被@Aspect标注的切面了 -->
<!-- 开启自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LogAspect {
}
@Pointcut
注解来表示(作为切入点签名的方法必须返回void
类型)@Pointcut(value="", argNames = "")
@Aspect
public class LogAspect {
// 也可以在通知上定义,当需要复用切入点的时候
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
// 返回值 必须是void类型
public void log() {
}
}
通知是跟一个切入点表达式关联起来的,并且在切入点匹配的方法执行之前或者之后或者前后运行。 切入点表达式可能是指向已命名的切入点的简单引用或者是一个已经声明过的切入点表达式,通知的类型就是我们前面提到过的类型
@Before
注解声明前置通知@Before(value = "", argNames = "")
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut() 切入点表达式
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void logPointcut() {
}
/**
* @Before 前置通知
* value:指定切入点表达式或命名切入点;
* argNames:与Schema方式配置中的同义;
*/
@Before("logPointcut()")
public void before() {
System.out.println("前置通知");
}
}
@After
注解来声明。最终通知必须准备处理正常返回和异常返回两种情况。通常用它来释放资源。相当于异常处理里finally的代码@After(value = "", argNames = "")
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut() 切入点表达式
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void logPointcut() {
}
/**
* @After 后置通知
*/
@After(value = "logPointcut()")
public void after() {
System.out.println("后置通知");
}
}
@AfterReturning
注解来声明@AfterReturning(value="",pointcut="",returning="",argNames="")
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut() 切入点表达式
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void logPointcut() {
}
/**
* 不获取方法的返回值
*/
@AfterReturning(value = "logPointcut()")
public void AfterReturning1() {
System.out.println("异常通知");
}
/**
* 获取方法的返回值
* returning的赋值的名字,必须跟通知方法中参数的名字保持一致
*/
@AfterReturning(value = "logPointcut()", returning = "val")
public Object afterReturning(Object val) {
System.out.println("返回后通知");
return val;
}
}
@AfterThrowing
注解来声明@AfterThrowing(value="",pointcut="",throwing="",argNames="")
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut() 切入点表达式
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void logPointcut() {
}
/**
* @AfterThrowing 异常通知
* value:指定切入点表达式或命名切入点;
* throwing:异常类型。
*/
@AfterThrowing("logPointcut()")
public void afterThrowing() {
System.out.println("异常通知");
}
/**
* 如果想要限制通知只在某种特定的异常被抛出的时候匹配,同时还想知道异常的一些信息。
* 那我们就需要使用throwing属性声明响应
*/
@AfterThrowing(value = "logPointcut()", throwing = "exception")
public void afterThrowing(Exception exception) {
System.out.println("异常通知");
}
}
@Around
注解;@Around(value = "", argNames = "")
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut() 切入点表达式
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void logPointcut() {
}
/**
* @Around 环绕通知
* 比如 缓存切面,如果缓存中有值,就返回该值,否则调用proceed()方法
* value:指定切入点表达式或命名切入点;
* 注意 第一个参数必须是 ProceedingJoinPoint对象 具体这个类的更多详细使用看附录:
*/
@Around(value = "logPointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知1");
Object obj = pjp.proceed();
System.out.println("环绕通知2");
return obj;
}
}
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAdviceParamsAspect {
// 注意参数的个数必须一致,否则匹配不到
@Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)", argNames = "id,name")
public void testArgs(Object id, Object name) {
System.out.println(id);
System.out.println(name);
}
}
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAdviceParamsAspect {
// args、argNames的参数名与testArgs()方法中参数名 保持一致
@Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)", argNames = "id,name")
public void testArgs(Object id, Object name) {
System.out.println(id);
System.out.println(name);
}
// 也可以不用argNames
@Before(value = "execution(* com.wener.example.aop.aspect.*.*(..))&& args(id,name)")
public void testArgs(Object id, Object name) {
System.out.println(id);
System.out.println(name);
}
@Around(value = "execution(* com.wener.example.aop.aspect.*.*(..))&&(args(id,name,..))", argNames = "pjp,id,name")
public Object testAroundArgs(ProceedingJoinPoint pjp, Object id, Object name) throws Throwable {
System.out.println("Around之前");
Object obj = pjp.proceed();
System.out.println();
return obj;
}
}
public interface AspectDao {
public void test();
public void testParams(int id, String name);
public void testParams(Joinpoint jp, int id, String name);
}
@Component("aspectDao")
public class AspectDaoImpl implements AspectDao {
@Override
public void test() {
System.out.println("核心测试方法");
}
@Override
public void testParams(int id, String name) {
System.out.println("带参数的方法:" + "ID:" + id + "name:" + name);
}
}
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aspect.xml");
AspectDao dao = (AspectDao) context.getBean("aspectDao");
dao.test();
dao.testParams(1,"hello");
<aop:aspectj-autoproxy/>
来开启注解风格的@AspectJ支持;如果比较喜欢使用XML格式,Spring2.0也提供了使用新的"aop"命名空间来定义一个切面。 和使用@AspectJ风格完全一样,切入点表达式和通知类型同样得到了支持
AOP配置元素 用途 <aop:config>
顶层的AOP配置元素,大多数的 <aop:*>
必须包含在<aop:config>
元素内<aop:aspect>
定义一个切面 <aop:pointcut>
定义一个切点 <aop:advisor>
定义AOP通知器 <aop:before>
定义AOP前置通知 <aop:around>
定义AOP环绕通知 <aop:after-returning>
定义AOP返回通知 <aop:after-throwing>
定义AOP异常通知 <aop:after>
定义AOP后置通知(不管被通知的方法是否执行成功) <aop:aspectj-autoproxy>
启用@Aspect注解的切面 <aop:declare-parents>
以透明的方式为被通知的对象引入额外的接口
<aop-config>
,在配置文件中,我们可以声明多个<aop-config>
。<aop:config>
元素内部。<aop:config>
可以包含pointcut,advisor和aspect元素 (注意这三个元素必须按照这个顺序进行声明)<beans
...
xmlns:aop="http://www.springframework.org/schema/aop">
...
<aop:config>
</aop:config>
</beans>
<aop:aspect>
来声明<aop:config>
<aop:aspect id="myAspect" ref="myBean">
...
</aop:aspect>
</aop:config>
<bean id="myBean" class="...">
...
</bean>
<aop:config>
元素中定义,使用<aop:pointcut>
声明,这样多个切面和通知就可以共享该切入点,你也可以在切面中定义<aop:config>
<aop:pointcut id="servicePointcut"
expression="execution(* *.*(..))"/>
</aop:config>
<aop:config>
<aop:aspect id="myAspect" ref="myBean">
<!--这个切入点只能在该 切面中使用 -->
<aop:pointcut id="servicePointcut"
expression="execution(* *.*(..))"/>
</aop:aspect>
</aop:config>
和@AspectJ风格一样,基于xml的风格也支持5种通知类型并且两者具有同样的语义
<aop:aspect>
中使用<aop:before>
元素来声明它<aop:config>
<aop:pointcut id="servicePointcut"
expression="execution(* *.*(..))"/>
<aop:aspect id="beforeExample" ref="myBean">
<aop:before
pointcut-ref="servicePointcut"
method="doBefore"/>
</aop:aspect>
</aop:config>
<aop:aspect>
里面使用<aop:after-returning>
声明,通知方法可以得到返回值。使用returning属性来指定传递返回值的参数名。<aop:aspect id="afterReturningExample" ref="myBean">
<aop:after-returning
pointcut-ref="servicePointcut"
method="doAfterReturning"/>
...
</aop:aspect>
<aop:aspect id="afterReturningExample" ref="myBean">
<aop:after-returning
pointcut-ref="servicePointcut"
method="doAfterReturning"/>
...
</aop:aspect>
?
<aop:aspect>
中使用 <after-throwing>
元素来声明,还可以使用throwing属性来指定传递异常的参数名<!-- 无返回值 -->
<aop:aspect id="afterThrowingExample" ref="myBean">
<aop:after-throwing
pointcut-ref="servicePointcut"
throwing="exception"
method="doAfterThrowing"/>
...
</aop:aspect>
<aop:aspect>
中使用<aop:after>
元素来声明<aop:aspect id="afterFinallyExample" ref="myBean">
<aop:after
pointcut-ref="servicePointcut"
method="doAfter"/>
...
</aop:aspect>
<aop:aspect id="aroundExample" ref="myBean">
<aop:around
pointcut-ref="servicePointcut"
method="doAround"/>
...
</aop:aspect>
在同一个连接点上应用不止一个切面时, 除非明确指定, 否则它们的优先级是不确定的
切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定.
实现 Ordered 接口, getOrder() 方法的返回值越小, 优先级越高.若使用 @Order 注解, 序号出现在注解中,值越小优先级越高
@Aspect
@Component
public class LoggingAspect implements Ordered {
@Override
public int getOrder() {
return 2;
}
}
@Aspect
@Component
public class ValidateAspect implements Ordered {
@Override
public int getOrder() {
return 1;
}
}
@Order(2)
@Aspect
@Component
public class LoggingAspect {
}
@Order(1)
@Aspect
@Component
public class ValidateAspect {
}
方法 | 说明 |
---|---|
Signature getSignature(); | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs(); | 获取连接点方法运行时的入参列表 |
Object getTarget(); | 获取连接点所在的目标对象 |
Object getThis(); | 获取代理对象本身 |
方法名 | 功能 |
---|---|
Object proceed() throws Throwable | 执行目标方法 |
Object proceed(Object[] var1) throws Throwable | 传入的新的参数去执行目标方法 |
Aspect
@Component
public class JoinPointerAspect {
/**
* 定义一个切入点表达式,用来确定哪些类需要代理
*/
@Pointcut("execution(* com.wener.example.aop.aspect.*.*(..))")
public void declareJoinPointer() {}
/**
* 前置方法,在目标方法执行前执行
* @param joinPoint 封装了代理方法信息的对象,若用不到则可以忽略不写
*/
@Before("declareJoinPointer()")
public void beforeMethod(JoinPoint joinPoint){
System.out.println("目标方法名:" + joinPoint.getSignature().getName());
System.out.println("目标方法所属类的名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + joinPoint.getTarget());
System.out.println("代理对象自己:" + joinPoint.getThis());
}
/**
* 环绕方法,可自定义目标方法执行的时机
* @param pjd JoinPoint的子接口,添加了
* Object proceed() throws Throwable 执行目标方法
* Object proceed(Object[] var1) throws Throwable 传入的新的参数去执行目标方法
*
* @return 此方法需要返回值,返回值视为目标方法的返回值
*/
@Around("declareJoinPointer()")
public Object aroundMethod(ProceedingJoinPoint pjd){
Object result = null;
try {
//前置通知
System.out.println("目标方法执行前...");
//执行目标方法
//result = pjd.proeed();
//用新的参数值执行目标方法
result = pjd.proceed(new Object[]{"hello","world"});
//返回通知
System.out.println("目标方法返回结果后...");
} catch (Throwable e) {
//异常通知
System.out.println("执行目标方法异常后...");
throw new RuntimeException(e);
}
//后置通知
System.out.println("目标方法执行后...");
return result;
}
}
小礼物走一走,来简书关注我
标签:最简 运行时 pat null wing 代理 pojo ida beans
原文地址:https://www.cnblogs.com/kelelipeng/p/11392766.html