4-Spring-AOP

        Spring-AOP:AOP + Aspects;AOP框架之一,其他比如还有AspectJ

                Aspect-Oriented-Programming(面向切面编程),一种编程思想。

                切面:Aspect,由切入点额外功能组成。

        作用:提供了新的编程角度,不再只是考虑类、对象,而可以考虑切面。切面和目标形成代理,解决项目业务中额外功能冗余的问题。 

        实现方式:JDK动态代理;CGLIB动态代理

代理模式_头秃人菜的博客-CSDN博客


AOP使用

        用aop最多的场景:事务控制;其他时候很少使用

  • 导入依赖:
<!-- 1> 负责和AspectJ框架集成。Spring-AOP 和 AspectJ 都是AOP框架,一个面向spring工厂中的bean,一个可以面向所有java对象 
	 2> aspectweaver 即 AspectJ 的库。
	 3> spring-AOP模块,并没有独立提供完整的AOP实现,而是集成了【AspectJ框架(AOP框架)】,比如所有的切入点表达式来自AspectJ
	 4> spring-aspects就是负责集成AspectJ。
-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>
<!-- spring-aspects 会传递导入 
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
      <scope>compile</scope>
    </dependency>
 	而aspectweaver 即 AspectJ 的一个库,(可以github搜索“AspectJ”,查看在Github上的镜像)。
	spring-AOP模块,并没有独立提供完整的AOP实现,而是集成了【AspectJ框架(AOP框架)】
	spring-aspects就是负责集成AspectJ。
-->
<!-- AOP联盟,可省略,spring4.3.6中的 aop模块中添加了其中的api( 兼容了AOP联盟 )
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
-->
  • 准备Target:
public class UserServiceImpl implements UserService{
    private UserDAO userDAO;
    @Override
    public void updateUser(User user) {
        System.out.println("update in service===============");
        userDAO.updateUser(user);
    }
    @Override
    public void insertUser(User user) {
        System.out.println("insert in service===============");
        userDAO.insertUser(user);
    }
    // set/get省略
}
  • 准备Advice:
public class MyAdvice {//POJO 类中可以包含多个 额外功能,此处暂且定义一个
    public void beforezhj() {//前置额外功能
        System.out.println("before~~~~");//模拟前置的额外功能逻辑
    }
}
  • 编织Weave:

        所谓编织,即,将Target 和 Advice 组装 形成代理。

        当然组装过程由spring管理,开发者只需要做出配置,告知spring需要组装谁即可

<!-- 声明 Target + Advice -->
<!-- 声明 Target -->
<bean id="userService" class="com.zhj.service.UserServiceImpl">
    <!-- 为userDAO属性赋值,值为id=“userDAO”的组件 -->
    <property name="userDAO" ref="userDAO"/>
</bean>
<!-- Advice -->
<bean id="myAdvice" class="com.zhj.advice.MyAdvice"/>

<!-- 编织 配置 -->
<aop:config>
    <!-- ref="引入MyAdvice" -->
    <aop:aspect ref="myAdvice">
        <!-- 切入点=pointcut
 			execution()表达式:描述切入位置
            组成:修饰符   返回值      包      类  方法名  参数表
                 public Integer com.xx.xxx.AA.xxxXXX(int,String)
            * com.service.UserServiceImpl.*(..):com.service包下UserServiceImpl类中,返回值修饰符任意,方法名任意,参数表任意
            * com.service.UserServiceImpl.queryUser(..):同上,只是方法名不是任意,而是 ”queryUser“
		-->
        <aop:pointcut id="pc" expression="execution(* com.zhj.service.UserServiceImpl.*(..))"/>
        <!-- aop:before 前置切入
			 method="MyAdvice类中的方法" pointcut-ref="beforezhj切入的位置" -->
        <aop:before method="beforezhj" pointcut-ref="pc"/>
    </aop:aspect>
</aop:config>
  • 测试:
UserService userService = (UserService)context.getBean("userService");
userService.insertUser(new User(...));

Advice种类

  • 前置额外功能:
public class MyAdvicee {
    public void beforezhj() {
        System.out.println("before~~~~");
    }
}
  • 后置额外功能:
public class MyAdvicee {
    public void beforezhj() {...}
	// 在核心功能执行并返回后,执行,ret9核心功能返回值,如果核心功能方法是void,则ret9=null
    public void myAfterReturning(Object ret9){
        System.out.println("after~~~~:"+ret9);
    }
}
  • 环绕额外功能:
public class MyAdvicee {
    public void beforezhj() {...}
    public void myAfterReturning(Object ret9){...}
    /** 
    	在核心功能前后 都执行
    	p.proceed();==> 调用核心功能,即控制了核心功能的执行,进而完成环绕效果
    **/
    public Object myInterceptor(ProceedingJoinPoint p) throws Throwable {
        System.out.println("interceptor_pre~~~~");// 前
        Object ret = p.proceed();//核心功能执行,注意要接收返回值
        System.out.println("interceptor_post~~~~");// 后
        return ret;//注意:要向上返回核心功能的返回值,否则,调用此代理的组件将得不到核心功能的返回值
    }
}
  • 异常额外功能:
public class MyAdvicee {
    public void beforezhj() {...}
    public void myAfterReturning(Object ret9){...}
    public Object myInterceptor(ProceedingJoinPoint p) throws Throwable {...}
    // 核心功能中抛出异常时执行
    public void myThrows(Exception ex){
        System.out.println("throws");
        System.out.println("===="+ex.getMessage());
    }
}
  • 编织:
<aop:config>
    <aop:aspect ref="myAdvicee">
        <aop:pointcut id="pc" expression="execution(* com.zhj.service.UserServiceImpl.*(..))"/>
        <aop:before method="beforezhj" pointcut-ref="pc"/>
        <!-- returning="ret9" myAfterReturning方法的参数 -->
        <aop:after-returning method="myAfterReturning" returning="ret9" pointcut-ref="pc"/>
        <aop:around method="myInterceptor" pointcut-ref="pc"/>
        <!-- throwing="ex" myThrows方法的参数 -->
        <aop:after-throwing method="myThrows" pointcut-ref="pc" throwing="ex"/>
        <aop:after ...><!-- after-returning:目标返回值后执行
                        after:目标之后必定执行,即使目标抛异常,比前者更强硬 -->
    </aop:aspect>
</aop:config>

切入点表达式

  • execution:
1>* com.service.UserServiceImpl.queryUser(..)
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:queryUser
    参数表:任意
2>* com.service.UserServiceImpl.*(..)
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:所有,任意
    参数表:任意
3>* com.service.*.*(..)
    返回值:任意
    包:com.service
    类:所有,任意
    方法:所有,任意
    参数表:任意
4>* com..*.*(..)
    返回值:任意
    包:com包,及其所有子包(com.a, com.b, com.c.cc)
    类:所有,任意
    方法:所有,任意
    参数表:任意
5>* *(..)    不建议
    返回值:任意
    包:任意
    类:所有,任意
    方法:所有,任意
    参数表:任意
6>* com.service.UserServiceImpl.query*(..)  【技巧:批量切入】
    返回值:任意
    包:com.service
    类:UserServiceImpl
    方法:所有,任意
    参数表:任意
  *注意:尽量精确,避免不必要的切入
  • within:
within(com.service.UserServiceImpl) 类中的所有方法
within(com..UserServiceImpl) com包和com子包下的UserServiceImpl类中的所有方法
    尽量写精确,Spring查找效率高

<aop:pointcut id="pc" expression="within(com..UserServiceImpl)"/>
  • args:
args(int,String,com.entity.User) 参数表如此的方法

<aop:pointcut id="pc" expression="args(int,String,com.entity.User)"/>
  • 联用:
and or not
与  或  非

多个表达式联合使用Spring查找效率更高,如within + args的组合
一定是不同种类的表达式之间使用
not不能用在第一个表达式前,即不能放在最开始
<aop:pointcut id="pc" expression="execution(* com.zhj.service.UserServiceImpl.*(..)) and args(com.User)"/>
<aop:pointcut id="pc" expression="within(com.service.UserServiceImpl) or args(com.User)"/>
<aop:pointcut id="pc" expression="within(com.service.UserServiceImpl) and not args(com.User)"/>

@AspectJ注解

        使用AspectJ注解简化开发

@Aspect //AspectJ的注解
public class MyAdvice2 {
    private final String pc = "execution(* com.xxx.service.UserServiceImpl.*(..))";

    @Before(pc) //AspectJ的注解
    public void myBefore(){
        System.out.println("before advice~~~~~~~03!!!!!");
    }

    @AfterReturning(value = pc,returning = "ret03") //AspectJ的注解
    public void myAfter(Object ret03){
        System.out.println("after~~~~~:"+ret03);
    }

    @Around(pc) //AspectJ的注解
    public Object myInterceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("tx begion~~~~");
        Object ret = joinPoint.proceed();//target的方法执行
        System.out.println("tx end~~");
        return ret;//向上返回
    }

    @AfterThrowing(value = pc,throwing = "ex") //AspectJ的注解
    public void myThrows(Exception ex){
        System.out.println("ex~~~~:"+ex.getMessage());
    }
}
<!-- 开启 @AspectJ支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

@Component注解

<!-- 可以扫描包下的所有类,类中的注解会被识别 -->
<context:component-scan base-package="com.zhj.advice"/>
@Aspect
@Component // <bean ...>
public class MyAdvice2 {
    //...
}

切面的执行顺序

        当多个切面,经过同一个方法时,默认先声明(配置文件中)的切面先经过

        可使用 order 属性明确定义顺序(数值小的优先执行)

  • 配置文件方式:
    <!-- Advice -->
    <bean id="aspect03" class="com.zhj.advice.MyAdvice"/>
    <bean id="aspect04" class="com.zhj.advice.MyAdvice3"/>
    
    <aop:config proxy-target-class="true">
        <aop:aspect ref="aspect03" order="2">
            <aop:pointcut id="pc03" expression="execution(* com.zhj.service.UserServiceImpl.queryUsers(..))"/>
            <aop:before method="myBefore" pointcut-ref="pc03"/>
        </aop:aspect>
        <aop:aspect ref="aspect04" order="1">
            <aop:pointcut id="pc03" expression="execution(* com.zhj.service.UserServiceImpl.queryUsers(..))"/>
            <aop:before method="myBefore" pointcut-ref="pc03"/>
        </aop:aspect>
    </aop:config>
  • 注解方式: 
@Aspect
@Order(1) //效果同配置文件
public class MyAdvice2 {
    //...
}

        如果项目中两种定制方式都存在,order 依然有效


手动自动代理

        如果某些类不在 IOC 容器中,想要切入,或者想脱离IOC容器单独AOP

/**
 * Spring提供如下实现,可以自定义 Advice 组件
 * MethodBeforeAdvice
 * AfterReturningAdvice
 * MethodInterceptor
 * ThrowsAdvice
 */
public class MyAdviceDemo implements MethodBeforeAdvice {//前置额外功能
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("before");
    }
}

class Test{
    public static void main(String[] args) {
        //代理工厂
        ProxyFactory factory = new ProxyFactory(new User());
//        factory.addInterface(XXX.class);//没有接口可以不写,则会使用CGLIB代理
        factory.addAdvice(new MyAdviceDemo());
        User proxy = (User) factory.getProxy();
        // this is a method call on the proxy!
        proxy.getId();
    }
}

源码解析

        构造 --> set  --> before init --> init --> post init --> destory

        init很少用一般不写

        后处理:before init + post init,对bean的再加工,力度较强

        代理的定制过程发生在 post init 过程中

AbstractAutowireCapableBeanFactory___doCreateBean{
    //.....
    if (instanceWrapper == null) {
        instanceWrapper = createBeanInstance(beanName, mbd, args);//完成单例bean创建
    }
    //.....
    try {
        populateBean(beanName, mbd, instanceWrapper);`
            if (exposedObject != null) {
                // 对bean后处理,beforeInit  init  postinit
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
    }
    //.....
}

AbstractAutowireCapableBeanFactory___initializeBean(){//是否所有bean都经历这个过程??		
    //.....
    if (mbd == null || !mbd.isSynthetic()) {
        // BeforeInit
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);`
    }
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);`//Init
    }catch (Throwable ex) {
        throw new BeanCreationException(...);` 
    }
    if (mbd == null || !mbd.isSynthetic()) {
        //AfterInit ,在此后处理中完成代理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);`
    }
    return wrappedBean;
}

AbstractAutowireCapableBeanFactory___applyBeanPostProcessorsAfterInitialization(){
    Object result = existingBean;
    // 遍历众多 BeanPostProcessor,其中有一个是:AbstractAutoProxyCreator,会完成代理的定制
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessAfterInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;

}

AbstractAutoProxyCreator___postProcessAfterInitialization(){
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);`
        if (!this.earlyProxyReferences.contains(cacheKey)) {
          	return wrapIfNecessary(bean, beanName, cacheKey);//完成从Target到Proxy的定制
		}
    }
    return bean;
}

AbstractAutoProxyCreator___wrapIfNecessary(){
    //.....
    if (specificInterceptors != DO_NOT_PROXY) {
        Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, 
                                    new SingletonTargetSource(bean));
        //.....
    }
    //.....
}

AbstractAutoProxyCreator___createProxy(){
    //.....
    return proxyFactory.getProxy(getProxyClassLoader());//new ProxyFactory(),然后调用此方法,构建代理
    //.....
}

ProxyFactory___getProxy(){
	 return createAopProxy().getProxy(classLoader);
}
ProxyFactory___createAopProxy(){
	return getAopProxyFactory().createAopProxy(this); // 创建代理的Factory,Factory中getProxy获得代理
}

DefaultAOPProxyFactory___createAopProxy(){
    // 是否积极优化,默认false,是否直接代理目标类(需要配置,默认false),是否有提供接口(如UserService)
    if (config.isOptimize() || config.isProxyTargetClass() ||
        hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException(...);
        }
        // 如果目标类是接口     如果目标类已是代理类
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);//使用cglib代理,其中的getProxy方法最终生成代理
    }else {
        return new JdkDynamicAopProxy(config);//使用jdk代理,其中的getProxy方法最终生成代理
    }
}

        如上:如果明确设置了使用cglib 或 目标类没有接口,且目标类不是接口,也不是已代理的类,则使用cglib代理,其他情况都使用jdk代理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值