• 在Intellij上面导入项目 & AOP示例项目 & AspectJ学习 & Spring AoP学习


    为了学习这篇文章里面下载的代码:http://www.cnblogs.com/charlesblc/p/6083687.html

    需要用Intellij导入一个已有工程。源文件原始内容也可见:link

    选择 Import Project -> "Create Project from existing sources" ->选择root目录,一步步选择完毕。

    为了从百度maven服务器更快的下载,在pom.xml最下面加上以下repo地址:

    <repositories>
        <repository>
            <id>nexus-public</id>
            <url>http://maven.scm.baidu.com:8081/nexus/content/groups/public</url>
        </repository>
        <repository>
            <id>nexus-public-snapshots</id>
            <url>http://maven.scm.baidu.com:8081/nexus/content/groups/public-snapshots</url>
        </repository>
    </repositories>

    然后可能需要在报错的文件里用 option+enter进行一些错误的更正。

    然后在project structure里面进行一些artifact的添加,就可以生成JAR。

    一直在报错找不到依赖文件。看了一下 Project里面有两个module,删掉其中的main,只留aop。然后就不再报错啦。。。

    然后看例子。

    demo4

    CGLib 动态代理

    我们使用开源的 CGLib 类库可以代理没有接口的类,这样就弥补了 JDK 的不足。

    demo7

    抛出异常AOP

    Hello! Jack
    ---------- Throw Exception ----------
    Target Class: aop.demo7.GreetingImpl
    Method Name: sayHello
    Exception Message: Error
    -------------------------------------
    Exception in thread "main" java.lang.RuntimeException: Error
    ......
    
    Process finished with exit code 1

    demo8 

    Spring AOP:引入增强

    以上提到的都是对方法的增强,那能否对类进行增强呢?用 AOP 的行话来讲,对方法的增强叫做 Weaving(织入),而对类的增强叫做 Introduction(引入)。而 Introduction Advice(引入增强)就是对类的功能增强,它也是 Spring AOP 提供的最后一种增强。

    @Component
    public class GreetingIntroAdvice extends DelegatingIntroductionInterceptor implements Apology {
    
    
        public void saySorry(String name) {
            System.out.println("Sorry! " + name);
        }
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            return super.invoke(invocation);
        }
    }

    然后在spring的配置文件里面这样配:

    <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces" value="aop.demo8.Apology"/>
            <property name="target" ref="greetingImpl"/>
            <property name="interceptorNames" value="greetingIntroAdvice"/>
            <property name="proxyTargetClass" value="true"/>
    </bean>

    需要注意 proxyTargetClass 属性,它表明是否代理目标类,默认为 false,也就是代理接口了,此时 Spring 就用 JDK 动态代理。如果为 true,那么 Spring 就用 CGLib 动态代理。这简直就是太方便了.

    9. Spring AOP:切面

    配置如下:

    <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="advice" ref="greetingAroundAdvice"/>
            <property name="pattern" value="aop.demo9.GreetingImpl.good.*"/>
        </bean>
    
        <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target" ref="greetingImpl"/>
            <property name="interceptorNames" value="greetingAdvisor"/>
            <property name="proxyTargetClass" value="true"/>
        </bean>

    10. Spring AOP:自动代理(扫描 Bean 名称)

    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames" value="*Impl"/>
            <property name="interceptorNames" value="greetingAroundAdvice"/>
            <property name="optimize" value="true"/>
        </bean>

    通过以上配置,就可以自动扫描bean进行匹配。

    以上使用 BeanNameAutoProxyCreator 只为后缀为“Impl”的 Bean 生成代理。
    需要注意的是,这个地方我们不能定义代理接口,也就是 interfaces 属性,因为我们根本就不知道这些 Bean 到底实现了多少接口。
    此时不能代理接口,而只能代理类。所以这里提供了一个新的配置项,它就是 optimize。若为 true 时,则可对代理生成策略进行优化(默认是 false 的)。
    也就是说,如果该类有接口,就代理接口(使用 JDK 动态代理);如果没有接口,就代理类(使用 CGLib 动态代理)。
    而并非像之前使用的 proxyTargetClass 属性那样,强制代理类,而不考虑代理接口的方式。可见 Spring AOP 确实为我们提供了很多很好地服务。

    11. Spring AOP:自动代理(扫描切面配置)

    如果既要自动扫描bean,并且匹配方法,可以用下面的

       <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="pattern" value="aop.demo11.GreetingImpl.good.*"/>
            <property name="advice" ref="greetingAroundAdvice"/>
        </bean>
    
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
            <property name="optimize" value="true"/>
        </bean>

    但是匹配的时候,还是有一些问题。很麻烦。

    在 Spring 配置文件中,仍然会存在大量的切面配置。然而在有很多情况下 Spring AOP 所提供的切面类真的不太够用了,
    比如:想拦截指定注解的方法,我们就必须扩展 DefaultPointcutAdvisor 类,自定义一个切面类,然后在 Spring 配置文件中进行切面配置。
    不做不知道,做了您就知道相当麻烦了。

    12. Spring + AspectJ(基于注解:通过 AspectJ execution 表达式拦截方法)

    主要代码如下:

    @Aspect
    @Component
    public class GreetingAspect {
    
        @Around("execution(* aop.demo12.GreetingImpl.*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            before();
            Object result = pjp.proceed();
            after();
            return result;
        }
    
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }

    下面重点来分析一下这个切点表达式:

    execution(* aop.demo.GreetingImpl.*(..))

    • execution():表示拦截方法,括号中可定义需要匹配的规则。

    • 第一个“*”:表示方法的返回值是任意的。

    • 第二个“*”:表示匹配该类中所有的方法。

    • (..):表示方法的参数是任意的。

    XML配置内容:

        <context:component-scan base-package="aop.demo"/>
    
        <aop:aspectj-autoproxy proxy-target-class="true"/>

    需要注意的是 proxy-target-class="true" 属性,它的默认值是 false,默认只能代理接口(使用 JDK 动态代理),当为 true 时,才能代理目标类(使用 CGLib 动态代理)。

    13. Spring + AspectJ(基于注解:通过 AspectJ @annotation 表达式拦截方法) 

    首先用annotation定义一个tag

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tag {
    }

    然后针对这个tag来写增强方法:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class GreetingAspect {
    
        @Around("@annotation(aop.demo13.Tag)")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            before();
            Object result = pjp.proceed();
            after();
            return result;
        }
    
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }

    最后,在方法上面打上tag就可以了:

    @Component
    public class GreetingImpl implements Greeting {
    
        @Tag
        public void sayHello(String name) {
            System.out.println("Hello! " + name);
        }
    }

    除了 @Around 注解外,其实还有几个相关的注解,稍微归纳一下吧:

    • @Before:前置增强

    • @After:后置增强

    • @Around:环绕增强

    • @AfterThrowing:抛出增强

    • @DeclareParents:引入增强

    此外还有一个 @AfterReturning(返回后增强),也可理解为 Finally 增强,相当于 finally 语句,它是在方法结束后执行的,也就说说,它比 @After 还要晚一些。

    最后一个 @DeclareParents 竟然就是引入增强!为什么不叫做 @Introduction 呢?我也不知道为什么,但它干的活就是引入增强。

    14. Spring + AspectJ(引入增强)

    首先要定义一个aspect类:

    @Aspect
    @Component
    public class GreetingAspect {
    
        @DeclareParents(value = "aop.demo14.GreetingImpl", defaultImpl = ApologyImpl.class)
        private Apology apology;
    }

    在这个接口上标注了 @DeclareParents 注解,该注解有两个属性:

    • value:目标类

    • defaultImpl:引入接口的默认实现类

    然后在实现一个ApologyImpl类:

    package aop.demo14;
    
    public class ApologyImpl implements Apology {
    
    
        public void saySorry(String name) {
            System.out.println("Sorry! " + name);
        }
    }

    从 Spring ApplicationContext 中获取 greetingImpl 对象(其实是个代理对象),可转型为自己静态实现的接口 Greeting,也可转型为自己动态实现的接口 Apology,切换起来非常方便。

    使用 AspectJ 的引入增强比原来的 Spring AOP 的引入增强更加方便了,而且还可面向接口编程(以前只能面向实现类),这也算一个非常巨大的突破。

    上面这一句指的是如下,可以直接转型为Greeting,而不需要转型为GreetingImpl这个类了

    public class Client {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("aop/demo14/spring.xml");
            Greeting greeting = (Greeting) context.getBean("greetingImpl");
            greeting.sayHello("Jack");
    
            Apology apology = (Apology) greeting;
            apology.saySorry("Jack");
        }
    }

    15. Spring + AspectJ(基于配置)

    仍然还是有用户不能尝试这些特性,因为他们还在使用 JDK 1.4(根本就没有注解这个东西),怎么办呢?没想到 Spring AOP 为那些遗留系统也考虑到了。

    demo15基本完全基于配置,因为代码很简单:

    package aop;
    
    public interface Greeting {
    
        void sayHello(String name);
    }

    而配置会复杂一些:

        <bean id="greetingImpl" class="aop.demo15.GreetingImpl"/>
    
        <bean id="greetingAspect" class="aop.demo15.GreetingAspect"/>
    
        <aop:config>
            <aop:aspect ref="greetingAspect">
                <aop:around method="around" pointcut="execution(* aop.demo15.GreetingImpl.*(..))"/>
            </aop:aspect>
        </aop:config>

    使用 <aop:config> 元素来进行 AOP 配置,在其子元素中配置切面,包括增强类型、目标方法、切点等信息。

    无论您是不能使用注解,还是不愿意使用注解,Spring AOP 都能为您提供全方位的服务。

    下面这张图非常好。

    给一张牛逼的高清无码思维导图,总结一下以上各个知识点:

    再来一张表格,总结一下各类增强类型所对应的解决方案:

    增强类型 基于 AOP 接口 基于 @Aspect 基于 <aop:config>
    Before Advice(前置增强) MethodBeforeAdvice @Before <aop:before>
    AfterAdvice(后置增强) AfterReturningAdvice @After <aop:after>
    AroundAdvice(环绕增强) MethodInterceptor @Around <aop:around>
    ThrowsAdvice(抛出增强 ThrowsAdvice @AfterThrowing <aop:after-throwing>
    IntroductionAdvice(引入增强) DelegatingIntroductionInterceptor @DeclareParents <aop:declare-parents>

    最后给一张 UML 类图描述一下 Spring AOP 的整体架构:

    最后,再记录一下原文地址:link1   link2(续)

    代码位置:/Users/baidu/Documents/Data/Work/Code/Demo_Code/aop_demo/

    (完) 

  • 相关阅读:
    正式搬家到博客园
    (SQL 技术篇)主键,外键,唯一约束,check约束
    Firefox 多个版本共存
    HTML5的视频格式之争
    jquery 提示简单效果插件 cluetip
    C# GUID的使用
    免费的jquery ui 收集
    js 验证身份证号码
    加速Web开发的9款知名HTML5框架
    Jquery中的CheckBox、RadioButton、DropDownList的取值赋值实现代码
  • 原文地址:https://www.cnblogs.com/charlesblc/p/6092842.html
Copyright © 2020-2023  润新知