spring 基础下

AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。主要的功能是:日志记录、性能统计、安全控制、事务处理、异常处理等等
AOP实现方式:
1、预编译:AspectJ
2、运行期动态代理(JDK动态代理、CGLib动态代理):SpringAOP、JbossAOP
Advice(通知)的类型:前置通知(Before advice)、返回后通知(After returning advice)、抛出异常后通知(After throwing advice)、后通知(After(finally)advice)、环绕通知(Around Advice)
Spring AOP实现有无接口的区别:
1、Spring AOP默认使用标准的JavaSE动态代理作为AOP代理,这使得任何接口(或接口集)都可以被代理(JDK动态代理)
2、Spring AOP中也可以使用CGLib代理(如果一个业务对象并没有实现一个接口)
对切面的理解
程序中的每一个模块或者说功能,任何一个模块中都要记录它的日志、事务、安全验证等等,给我们带来的工作量非常大。
当程序到达某种规模时,尤其是格式调整之类的,这种改动量是非常大的。如果通过切面方式,对开发人员是不可见的,默认地会对每一个子模块记录日志等这些工作。通过预编译或者动态代理的方式来执行这个功能,
对开发人员是透明,他不需要知道。
切面是和功能垂直的,也就是切面是横切与各个功能之上的
AOP几个相关概念
①切面---一个关注点的模块化,这个关注点可能会横切多个对象
②连接点--程序执行过程中的某个特定的点
③通知----在切面的某个特定的连接点上执行的动作
④切入点--匹配连接点的断言,在AOP中通知和一个切入点表达式关联
⑤引入----在不修改类代码的前提下,为类添加新的方法和属性
⑥目标对象-被一个或者多个切面所通知的对象
⑦AOP代理--AOP框架创建的对象,用来实现切面契约(包括通知方法执行等功能)
⑧织入---把切面连接到其他的应用程序类型或者对象上,并且创建一个被通知的对象,分为:编译时织入,执行时织入

Spring的AOP实现
·纯java实现,无需特殊的编译过程·,不需要控制类加载器层次
·目前只支持方法执行连接点(通知Spring Bean的方法执行)
·不是为了提供最完整的AOP实现(尽管它非常强大);而是侧重于提供一种AOP实现和Spring IOC容器之间的整合,用于帮助解决企业应用中的常见问题
·Spring AOP不会与AspectJ竞争,从而提供综合全面的AOP解决方案。

把对象类 切面类(与通过配置aop:config来指定普通类成为切面类不同,使用ProxyFactoryBean的切面类都需要继承AOP API并重写方法来实现传递通知)都作为
成员属性放在一个ProxyFactoryBear类中 通过在ProxyFactoryBear类中的方法,指定对象类的切入点并配置切面(不再是通过配置文件进行切面配置,而是在IOC容器中配置)。并且最后返回一个Object类(可以理解为对象类对象通过一系列切面类方法加工、植入通知后的结果对象)
1 核心:代理工厂(ProxyFactoryBean)
	*必备属性:代理目标类(target,可以使用引用bean或匿名bean,推荐后者)、通知(advisor或advice)
	*可选属性:代理接口(proxyInterfaces,使用JDK动态代理)、代理类属性(proxyTargetClass的值为true时,则使用cglib代理)
	2 切入点常用bean:NameMatchMethodPointcut
	*根据名称自动匹配方法,可以使用通配符的形式进行匹配,匹配结果放在数组mappedNames中
	*mappedNames节点可以使用list子节点进行设置匹配项(可以使用通配符)
	3 通知常用bean:DefaultPointcutAdvisor
	*必备属性:advice和pointcut
	*可以使用构造注入或设置注入的形式注入两个属性
 使用ProxyFactoryBean,通知和切入点可以由IOC容器管理
- 被代理类没有实现任何接口,用的是CGLIB动态代理,否则使用的是JDK代理
- ProxyFactoryBean为true,无论是否实现了接口,都强制使用CGLIB
- 如果proxyInterfaces属性设置为一个或者多个全限定接口名,使用的是JDK代理

Spring AOP API小结
一、Pointcut
1.实现之一:NameMatchMethodPointcut,根据方法名进行匹配
2.成员变量:mappedNames,匹配方法名集合
二、Advice
1.Before Advic -- 继承MethodBeforeAdvice接口
2.Throws Advice -- 继承ThrowsAdvice接口
3.After Returning Advice -- 继承AfterReturningAdvice接口
4.Interception Around Advice -- 继承MethodInterceptor接口
5.Introduction Advice
三、ProxyFactoryBean
1.不指定接口
2.指定接口
3.简化proxy使用
 注解方式实现Aspectj
@configuration
@EnableAspectjAutoProxy
public class Appcinfig{
}<aop:sapectj-autoproxy/>
AspectJ是编译期的AOP
检查代码并匹配连接点与切入点的代价是昂贵的
一个好的切入点应该包括以下几点
- 选择特定类型的连接点,如:execution,get,set,call,handler
- 确定连接点范围,如:within,withincode
- 匹配上下文信息,如:this,target,@annotation
@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并应用
用@Aspect注解的类可以有方法和字段,他们也可能包括切入点(pointcut),通知(Advice)和引入(introduction)声明
@Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使用@Component注释或者在xml配置bean
@Aspect注解是不能够通过类路径自动检测发现的,所以需要配合使用@Component注释或者在xml配置bean

一个类中的@Aspect注解标识它为一个切面,并且将自己从自动代理中排除
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
   <!-- configure properties of aspect here as normal -->
</bean>

package org.xyz;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class NotVeryUsefulAspect{
}
使用@Pointcut注解,方法的返回值类型必须是void
@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
利用注解的方式实现切面(之前是使用xml配置的方式)

在xml文件中配置

<aop:aspectj-autoproxy/>

在切面类的文件中,Component表示可以被识别为一个bean,Aspect表示是一个切面的类,pointcut的方法在注解上表明了切入点的类,before,afterReturning,afterThrowing,after与之前相似,其中的参数表示切入的方法返回值或者抛出的错误信息

@Component
@org.aspectj.lang.annotation.Aspect
public class Aspect {

  @Pointcut("execution(* com.aspectj.Biz.*(..))")
  public void pointcut() {
  }

  // @Pointcut("within(* com.aspect.*)")
  // public void bizPointcut() {
  // }

  @Before("pointcut()")
  public void before() {
    System.out.println("Before...");
  }

  @AfterReturning(pointcut = "pointcut()", returning = "returnValue")
  public void afterReturning(Object returnValue) {
    System.out.println("AfterReturning..." + returnValue);
  }

  @AfterThrowing(pointcut = "pointcut()", throwing = "e")
  public void afterThrow(RuntimeException e) {
    System.out.println("AfterThrowing..." + e.getMessage());
  }
  
  @After("pointcut()")
  public void after() {
    System.out.println("After...");
  }

}
使用around注解,实现环绕通知

  @Around("pointcut()")
  public Object around(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("Around before...");
    Object obj = pjp.proceed();
    System.out.println("Around after...");
    return obj;
  }
@around注解的最大特点是可以同时在方法执行前后都写入逻辑代码,around会在before之前执行,也会在after之前执行,环绕通知有可能抛出异常,我们可以根据业务需求抛出或者处理异常。
@After注解类似于finally,用于处理发生异常或未发生异常时的情况,即程序运行结束前的最后一行代码,一般用于释放资源使用,spring的声明式事务可能就是通过这种方式来最终关闭事务的。after会在afterreturning前面执行,即方法返回结果前执行。
@Before("表示式、连接点方法名()")@AfterReturing 可以使用returing绑定返回值 Object@AfterThrowing throwing同上@After finally
@Around 第一个参数必须是ProceedingJoinPoint proceed(),proceed(Object[])
详细说明:
Spring 中通知的类型:
Around     org.aopalliance.intercept.MethodInterceptor   栏截对目标对象方法的调用 
Before      org.springframework.aop.MethodBeforAdvice             在目标方法被调用之前调用     
After          org.springframework.aop.AfterReturningAdvice          当目标方法被调用之后调用
Thorws    org.springframework.aop.ThrowsAdvice                       当目标方法抛出异常时调用
程序正常执行顺序:
执行前 -环绕通知      Around
执行前 - 通知     Before
POINT - 切入点 方法前执行  @Before
POINT - 切入点 环绕方法前执行    @Around
POINT - 切入点 方法后执行  @AfterReturning
POINT - 切入点 环绕方法后执行                       @Around
执行后 - 通知        After         
执行后 - 环绕通知      Around
程序抛出异常执行顺序:
执行前 -环绕通知                                              Around
执行前 - 通知                                                    Before
POINT - 切入点 方法前执行                               @Before
POINT - 切入点 环绕方法前执行                       @Around
切入点异常处理通知                                             @AfterThrowing
异常处理通知                                                          Thorws
IOC即DI,不必调用者自己去new被调用对象,而是通过spring IOC容器把配置好的bean对象注入,可以通过设置注入即setter方法和构造器注入。bean装载可以通过xml配置设定,也可以同过设定扫描路径,然后通过注解来让容器识别到要装载的bean。aop面向切面编程,切面与业务是垂直的,不同业务往往都要做一些公共的类似的额外操作,在业务之前做,或在业务之后做,或在业务出了异常时做,或者在业务前后都要做,甚至这些要做的额外操作要用到业务本身的输入参数和业务完成的输出结果。比如业务一般都得记录日志,比如涉及数据更新的业务完成后都得伴随数据库操作,账户各种操作前都要验证用户权限,这些业务伴随的操作往往大致相似,如果每个业务都要写这些操作,特别繁琐,把这些操作提出来就成了切面,与业务分离。xml 和API方式都可以实现aop配置,pointcut是业务,aspect是切面,它俩怎么交互执行,怎么传参和调用结果,都可以通过xml和API方式实现。另外还有配置代理这一块比较蒙逼。最牛逼的是,之前看得傻了眼那么繁琐和复杂的xml,api方式用简单直观的aspectj方式竟然能等效实现,用的纯Java标签,在xml 里设一下自动代理。不过仅仅@Aspect容器不识别,要加上@Component 才识别。
连接点就是业务方法执行过程中的标记点,切入点是针对切面而言的,是准备aspect要素,而连接点是针对业务方法而言的,一个完成的切面是由advice(逻辑:日志、性能、权限控制等等逻辑)和pointcut构成的,这两个要素在一起就构成了对切入方法的所有工作。难点还是在ProxyFactory以及spring aop api的使用,以及用api的方式创建代理对象。
AspectJ小结

一、配置@AspectJ
- xml方式
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 注解方式
@Component
@Aspect
二、Pointcut
@Pointcut
使用@Pointcut注解,方法的返回值类型必须是void
三、Advice
1.Before advice2.After returning advice3.After throwing advice4.After (finally) advice5.Around advice6.给advice传递参数7.Advice的参数及泛型
切面实例化模型
- 这是一个高级主题
- "perthis"切面通过指定@Aspect注解perthis子句实现
- 每个独立的service对象执行时都会创建一个切面实例
- service对象的每个方法在第一次执行的时候创建切面实例,切面在service对象失效的同时失效
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect{
   private int someState;
   @Before(com.xyz.myapp.SystemArchitecture.businessService())
   public void recordServiceUsage(){
      //...
   }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lozhyf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值