A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

紫陌兰尘

初级黑马

  • 黑马币:

  • 帖子:

  • 精华:

AOP:
    1,切面 思想 :
        这是一个思想,可以在代码上实现,
        可以增加我们代码的扩展性,重用行,还可以提高开发效率.
        
        底层通过动态代理实现.
        
        spring框架优先使用 JDK的动态代理,如果不能使用会使用CGLIB实现.
        
    2,名词解释:
        目标对象    :    被代理的对象
        连接点        :    被代理对象的方法
        切入点(切点):    被代理对象的方法我们真正要增强方法
        通知        :    我们要增强一些什么
        切面        :    切入点+通知,也就是我们写的aop增强代码+配置文件
   
    3,aop实现:
        1)通知方式:
            前置通知    :    目标方法之前增强    org.springframework.aop.MethodBeforeAdvice
            后置通知    :    目标方法之后增强    org.springframework.aop.AfterReturningAdvice
            环绕通知(**):    目标方法前后都增强    org.aopalliance.intercept.MethodInterceptor
            异常抛出通知:    目标方法出现了异常后增强    org.springframework.aop.ThrowsAdvice (如果没有异常,不会执行)
            
        1)传统方式:
            (1)根据要增强的方式,选择一个接口去实现.重写里面的方法.
            (2)然后编写配置文件:
                定义目标:
                    <bean id="自己起ID名" class="目标的全路径"></bean>
                定义通知:
                    <bean id="自己起ID名" class="我们编写的AOP代码类的全路径"></bean>
                定义切入点:
                    <bean id="自己起ID名" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
                        <property name="pattern" value="正则表达式,类似.*Order"></property>
                    </bean>
                定义切面:
                    <bean id="自己起ID名" class="org.springframework.aop.support.DefaultPointcutAdvisor">
                        <property name="advice" ref="上面通知的ID"/>
                        <property name="pointcut" ref="上面切入点的ID"/>        
                    </bean>
                定义代理:
                    <bean id="自己起ID名" class="org.springframework.aop.framework.ProxyFactoryBean">
                        <property name="target" ref="上面目前的ID"/>
                        <property name="interceptorNames" value="上面切面的ID"/>
                        <!--这个配置要注意,如果要增强的目前是通过接口实现的使用以下配置-->
                        <property name="proxyInterfaces" value="目前实现接口的全路径"/>
                        <!--如果要增强的没有接口,使用以下配置,这两个配置不可以同时使用-->
                        <property name="proxyTargetClass">
                            <value>true</value>
                        </property>
                    </bean>
                    
            (3)简化配置文件:
                a.导入jar:直接copy
                b.配置文件支持:需要增加aop的支持,直接copy.
                c.配置文件编写:
                    定义目标:
                        <bean id="自己起ID名" class="目标的全路径"></bean>
                    定义通知:
                        <bean id="自己起ID名" class="我们编写的AOP代码类的全路径"></bean>
                    定义AOP:
                        <aop:config>
                            <!-- 定义切入点 -->
                            <aop:pointcut expression="execution(* cn.itheima.aop.IOrderService.*(..))" id="自己起ID名" />
                            <!-- 定义切面 -->
                            <aop:advisor advice-ref="通知的ID" pointcut-ref="上面切入点的ID" />
                        </aop:config>
                        
            (4)切点表达式:
                execution(<修饰符> <返回类型> <类路径> <方法名>(<参数列表>) <异常模式> )
                execution(public * cn.itheima.aop.IOrderService.*(..))
                execution(* cn.itheima.aop.IOrderService.*(..))
                execution(* cn.*.IOrderService.*(..))
                注意如果 第一个 * 表示的实际上是 public *
               
                配置多个
                <aop:pointcut expression="execution(* cn.*.IOrderService.*(..))||execution(* cn.itheima.aop.IOrderService.*(..))" id="自己起ID名" />
                    
        2)aspectJ方式:
            (1)aspectJ的通知类型:
                前置通知 Before 相当于 BeforeAdvice
                后置通知 AfterReturning 相当于 AfterReturningAdvice
                环绕通知 Around 相当于 MethodInterceptor
                抛出通知 AfterThrowing 相当于 ThrowAdvice(如果没有异常,不会执行)
                最终通知 After 不管是否异常,该通知都会执行(特有的类似于finally)
               
                对于AOP增强一个service的方法,我起码需要几个类?
               
            (2)实现方式有两种:
                xml配置文件
                注解开发
               
            (3)配置文件方式
                a.定义目标:
                    <bean id="自己起ID名" class="要增强的实现类"/>
                    
                b.定义通知:
                    这个aop的类可以不实现任何接口,就是一个普通的类.写一个方法
                    
                    //方法名可以自定定义,可以有一个参数JoinPoint jp,也可以无参
                    public void before(JoinPoint jp) {
                        System.out.println("拦截的目标类:" + jp.getSignature().getDeclaringTypeName());
                        System.out.println("拦截的方法名称:" + jp.getSignature().getName());
                        System.out.println("前置通知");
                    }
                    
                    配置上增加
                    <bean id="自己起ID名" class="我们编写的AOP代码类的全路径"/>
               
                c.定义切面:
                    <!-- 使用aop:config来声明  使用aop:aspect来配置切面 -->
                    <aop:config >
                        <aop:aspect ref="上面声明的通知ID">
                            <!-- 配置切入点 -->
                            <aop:pointcut expression="execution(* *.del(..))" id="自己起ID名"/>
                            <!-- 前置通知 可以不使用上面的切入点,自己声明 method表示具体使用哪个方法 -->
                            <aop:before method="before" pointcut="execution(* *.del(..))"/>
                            <!-- 前置通知 -->
                            <aop:before method="before1" pointcut-ref="引用上面声明的切入点ID"/>
                        </aop:aspect>
                    </aop:config>
                    
                d.其他通知:
                    后置:
                        // 后置通知 java代码
                        public void afterReturning() {
                            System.out.println("目标方法返回值:" + val);
                            System.out.println("后置通知");
                        }
                        
                        <aop:config>
                            <aop:aspect ref="userServiceAdvice">
                                <aop:after-returning method="afterReturning" pointcut="execution(* *.del(..))"/>
                            </aop:aspect>
                        </aop:config>
                        
                    环绕:
                        //环绕通知 java代码,他必须有一个参数 ProceedingJoinPoint pjp
                        public Object around(ProceedingJoinPoint pjp) throws Throwable {
                            System.out.println("环绕前....");
                            Object value = pjp.proceed(); // 执行目标行为
                            System.out.println("环绕后....");
                            return value;
                        }
                        
                        <aop:config >
                            <aop:aspect ref="userServiceAdvice">
                                <aop:pointcut expression="execution(* *.del(..))" id="delPointCut"/>
                                <aop:around method="around"  pointcut-ref="delPointCut"/>
                            </aop:aspect>
                        </aop:config>
                    
                e:通知上的参数:
                    除了环绕通知以外,所有的通知都可以有一个参数JoinPoint jp
                    注意导包:org.aspectj.lang.JoinPoint
                        拦截的目标类    :    jp.getSignature().getDeclaringTypeName());
                        拦截的方法名称    :    jp.getSignature().getName());
                        
                    环绕通知必须有参数:ProceedingJoinPoint pjp
                        执行目标行为    :    Object value = pjp.proceed();
                        有点类似我们拦截器的invoke方法.
                        
                    后置通知可以增加一个参数 Object val,
                        这个参数表示我们目标方法的返回值,
                        注意需要在配置文件上增加配置
                            <aop:after-returning method="afterReturning" pointcut-ref="delPointCut" returning="val"/>
                        returning="val"表示存在这个参数,参数名称为 val 要与代码里的参数名称一致
                        
                    异常通知可以增加一个参数 Throwable ex
                        这个参数表示目前抛出的异常,
                        注意需要在配置文件上增加配置
                            <aop:after-throwing method="afterThrowing" pointcut-ref="delPointCut" throwing="ex"/>
                        throwing="ex"表示存在这个参数,参数名称为 ex 要与代码里的参数名称一致
                        
                f:代理方案选择:
                    spring框架对于有接口的使用动态代理,没有接口的使用cglib.
                    我们可以强制使用cglib,需要配置 proxy-target-class="true"
                    <aop:config proxy-target-class="true"></aop:config>
                    
            (4)注解开发
                1)要是用spring的注解,我们要在配置文件中开启包扫描的注解
                    <context:component-scan base-package="cn.itheima" />
                  同时,要开启aop的aspectj注解自动代理
                    <!-- 开启aspectj注解自动代理 -->
                    <aop:aspectj-autoproxy />
                    <!-- 我们也可以强制使用cglib代理 -->
                    <!-- <aop:aspectj-autoproxy proxy-target-class="true"/> -->
                    
                2)编写通知类:这里所有和AOP相关的类都是 org.aspectj.lang 包下的
                    @Component//将当前类交给spring容器管理相当于<bean id="自己起ID名" class="我们编写的AOP代码类的全路径"/>
                    @Aspect // 声明当前的bean就是一个切面,而不是一个普通的bean
                    public class CustomerServiceHelper {
                    
                        @Before("execution(* *.s*(..))")
                        public void before() {
                            System.out.println("前置通知...");
                        }
                    }
                    
                    @Component
                    @Aspect
                    public class CustomerServiceHelper {
                        // 后置通知 returning = "value" 声明参数
                        @AfterReturning(value = "execution(* *.update(..))", returning = "value")
                        public void afterReturning(JoinPoint jp, Object value) {
                            System.out.println("后置通知,目标方法的返回是" + value);
                        }
                    }
                    
                    @Component
                    @Aspect
                    public class CustomerServiceHelper {
                        // 环绕通知
                        @Around("mypointcut()")
                        public Object around(ProceedingJoinPoint pjp) throws Throwable {
                            System.out.println("环绕前...");
                            Object value = pjp.proceed();
                            System.out.println("环绕后");
                            return value;
                        }
                    }
               


2 个回复

倒序浏览
黑马计划 来自手机 初级黑马 2018-3-5 17:26:56
沙发
顶顶顶顶
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马