spring面向切面

(1)AOP概念
面向切面编程,指扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来。 主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要意图:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
AOP特点:
采用横向抽取机制,取代了传统纵向继承体系重复性代码。
AOP底层实现:
AOP底层使用动态代理实现。包括两种方式:
(1)使用JDK动态代理实现。
(2)使用cglib来实现

  JDK动态代理实现:	只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
 1. 定义一个实现接口InvocationHandler的类		2. 通过构造函数,注入被代理类		3. 实现invoke( Object proxy, Method method, Object[] args)方法		4. 在主函数中获得被代理类的类加载器		5. 使用Proxy.newProxyInstance( )产生一个代理对象		6. 通过代理对象调用各种方法
 
 cglib动态代理实现:	针对类实现代理,对是否实现接口无要求。原理是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以被代理的类或方法最好不要声明为final类型。
 		1. 定义一个实现了MethodInterceptor接口的类	
 		2.  实现其intercept()方法,在其中调用proxy.invokeSuper( )	

代理方式的选择:

  1. 如果目标对象实现了接口,默认情况下回采用JDK的动态代理实现AOP,也可以强制使用cglib实现AOP
  2. 如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换
    AOP操作术语:
    Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
    Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.
    Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    Aspect(切面): 是切入点和通知(引介)的结合Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.
    Target(目标对象):代理的目标对象(要增强的类)Weaving(织入):是把增强应用到目标的过程,把advice 应用到 target的过程
    Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

**切入点:**在类里边可以有很多方法被增强,比如实际操作中,只是增强了个别方法,则定义实际被增强的某个方法为切入点。

**通知/增强:**增强的逻辑,称为增强,比如扩展日志功能,这个日志功能称为增强。包括:
前置通知:在方法之前执行

后置通知:在方法之后执行

异常通知:方法出现异常执行

最终通知:在后置之后执行

环绕通知:在方法之前和之后执行

切面:把增强应用到具体方法上面的过程称为切面。
使用表达式配置切入点:常用的表达式execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(1)execution(* cn.itcast.aop.Book.add(…))
(2)execution(* cn.itcast.aop.Book.(…))
(3)execution(
.(…))
(4) 匹配所有save开头的方法 execution(* save*(…))
//------------------------------//
1.首先定义一个借口UserDao
package com.offcn.dao;

public interface UserDao {
public void add();

}
//------------------------------------//
2.然后实现一个类UserDaoImpl ,相当于一个目标类
package com.offcn.dao.impl;

import com.offcn.dao.UserDao;

public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println(“增加成功”);
// throw new RuntimeException(“出错了!”);
}
}
//---------------------------------------------------------------//
3.
package com.offcn.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import java.util.Arrays;
//定义切面类AopError–相当于一个代理
public class AopError {
/JoinPoint 这个类所有动态代理类的信息/
public void affterError(JoinPoint joinPoint, RuntimeException e){
/joinPoint.getSignature() 这个方法是拿到你的动态代理的签名文件/
System.out.println(joinPoint.getSignature().getName()+“这个方法异常信息”+e.getMessage());
}
public void after(JoinPoint joinPoint){
System.out.println(“后置通知”);

}
/*环绕增强 传递的是其JoinPoint子类*/
public  void  around(ProceedingJoinPoint proceedingJoinPoint){
    System.out.println(proceedingJoinPoint.getTarget()+ Arrays.toString(proceedingJoinPoint.getArgs()));
    /*调用此方法执行目标对象相应的方法*//*这个方法又相当于一个分割线,也就是前置与后置的分割线*/
    try {
        proceedingJoinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println(proceedingJoinPoint.getSignature().getName());
}

public void before(){
    System.out.println("前置通知");
}

}

//-----------------------------------//核心配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<!--设置dao层-->
 <bean id="userDao" class="com.offcn.dao.impl.UserDaoImpl"></bean>
<!--设置Service层-->
<bean id="userService" class="com.offcn.service.impl.UserServiceDaoImpl">
    <property name="userDao" ref="userDao"></property>
</bean>


<!--设置增强aop-->
<bean id="aopError" class="com.offcn.aop.AopError"></bean>
<aop:config>
    <!--对那一方法或者哪一个类进行植入:切入点--><!--expression 每个参数对哪一个类进行注入,这句话execution代表所有方法,*代表全部方法-->
    <aop:pointcut id="pointcut" expression="execution(* com.offcn.service.UserService.*(..))"></aop:pointcut>
    <!--引入方法发增强bean    切面-->
    <aop:aspect ref="aopError">
        <!--在这个里面可以配置--><!--这个方法必须对应引入增强bean的方法,在这里面要设置切点-->
        <!--<aop:after-throwing method="affterError" pointcut-ref="pointcut" throwing="e"></aop:after-throwing>-->
        <!--后置增强-->

        <aop:after method="after" pointcut-ref="pointcut"></aop:after>
        <!--前置增强-->
        <aop:before method="before" pointcut-ref="pointcut"></aop:before>
        <!--环绕增强,在前后都做相关操作,相当于一个前置和一个后者增强-->
        <!--<aop:around method="around" pointcut-ref="pointcut"></aop:around>-->
    </aop:aspect>

</aop:config>
测试类如下: package com.offcn.test;

import com.offcn.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext(“applicationContext.xml”);
UserService userServiceDao = (UserService) app.getBean(“userService”);
userServiceDao.add();
}
}
console结果如下:
前置通知
增加成功了
后置通知com.offcn.service.impl.UserServiceImpl@71809907

猜你喜欢

转载自blog.csdn.net/weixin_42772943/article/details/83002370
今日推荐