美文网首页SSM
java-spring-2

java-spring-2

作者: 落云和枫 | 来源:发表于2018-11-27 10:33 被阅读0次

    一 学习大纲

           1.  动态代理设计模式(JDK和cglib)

           2.  AOP详解

           3.  AOP中几种通知类型

           4.两种实现方式(Schema-base和Aspectj)

    二 知识点详解

           1. AOP:中文名称 面向切面编程

           2 英文全称:Aspect Object Programming

           3 正常程序执行流程都行纵向执行流程,spring Aop 又叫面向切面编程,在原有的纵向执行流程中添加横切面

           3.1 不需要修改原有程序代码,优点:1.高扩展性,2. 原有功能相当于释放部分逻辑,让职务更加明确。

    4.面向切面编程是什么?

          4.1在程序原有的纵向流程执行中,针对某一个或者某一些方法添加通知,形成横切面向过程就叫做面向切面编程。

    5.常用概念

          5.1 原有功能:切点,pointcut

          5.2 前置通知:在切点之前执行的功能.before advice

          5.3 后置通知:在切点之后执行的功能,after advice

          5.4 在切点执行过程中出现的异常,会触发异常通知 throws advice

          5.5 所有功能总称叫做切面

          5.6 织入:把切面嵌入到原有功能的过程叫做织入

    6 spring提供了2种Aop实现方式

         6.1 Schema-based

               6.1.1 每个通知都需要实现接口或类

               6.1.2 配置spring配置文件时在 <aop:config> 配置

        6.2 AspectJ

              6.2.1 每个通知都不需要实现接口或类

             6.2.2 配置 spring 配置文件是在 <aop:config>的子标签 <aop:aspect> 中配置的

    二 Schema-based 实现步骤

    1. 导入jar包

    2. 新建通知类

    2.1 新建前置通知类,三个参数,agr0:切点方法对象Method 对象。

    agr1:切点方法参数,arg2:切点在哪个对象中

    public class MyBeforeAdvice implements MethodBeforeAdvice{

         @Overload

        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable{

            System.out.println("执行前置通知");

        }

    }


    2.2 新建后置通知类,agr0:切点方法返回值, arg1 切点方法对象,arg2 切点方法参数,arg3 切点方法所在类的对象。

    public class MyAfterAdvice implements AfterReturningAdvice{

         @Overload    

        public void afterReturning(Object arg0,Method arg,1, Object[] arg2, Object arg3) throws Throwable{

            System.out.println("执行后置通知");    

         }


    3 配置spring 配置文件

    引入 aop 命名空间 ,配置通知类的<bean>  配置切面

    applicationContext.xml

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

    <beans

    xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xsi:schemaLocation="http://www.springframework.org/sc

    hema/beans

    http://www.springframework.org/schema/beans/spring-be

    ans.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.

    xsd">

    <!-- 配置通知类对象,在切面中引入 -->

    <bean id="mybefore"   class="com.chen.advice.MyBeforeAdvice"></bean>

    <bean id="myafter"   class="com.chen.advice.MyAfterAdvice"></bean>

    <!-- 配置切面 -->

    <aop:config>

    <!-- 配置切点 -->

    <aop:pointcut expression="execution(*  com.chen.test.Demo.demo2())"  id="mypoint"/>

    <!-- 通知 -->

    <aop:advisor advice-ref="mybefore"  pointcut-ref="mypoint"/>

    <aop:advisor advice-ref="myafter"   pointcut-ref="mypoint"/>

    </aop:config>

    <!-- 配置 Demo 类,测试使用 ,ioc  控制反转特效,把对bean的引用 夺到spring 中去-->

    <bean id="demo" class="com.chen.test.Demo"></bean>

    </beans>


    测试类

    public class Test {

        public static void main(String[] args) {

        /**

            *通过ioc特性,自己不用创建demo

        */

         // Demo demo = new Demo();

            // demo.demo1();

            // demo.demo2();

            // demo.demo3();

            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

            Demo demo = ac.getBean("demo",Demo.class);

            demo.demo1();

            demo.demo2();

            demo.demo3();

        }

    }

    执行结果

    三  配置异常通知的步骤(AspectJ方式)

    1. 只有切点报异常才能出发异常通知,切点也就是 Demo

    2. 在 spring 中 有AspectJ 方式提供了异常通知的方法,如果想用 schema-base 实现实现特点的要求自己编写方法

    3. 实现步骤,新建类,在类写任意名称的方法

    public class MyThrowAdvice{

        public void myexception(Exception e1){

            System.out.println("执行异常通知"+e1.getMessage());

        }

    }


    3.1 在spring 配置文件中配置

        <aop:aspect> 的ref属性表示:方法在哪个类中

        <aop:xxxx/> 表示什么通知

        method:当触发这个通知时,调用哪个方法

        throwing:异常对象名,必须和通知中方法参数名相同(可以不在通知声明异常对象)

    applicationContext.xml

    <bean id="mythrow"  class="com.chen.advice.MyThrowAdvice"></bean>

        <aop:config>

            <aop:aspect ref="mythrow">

            <aop:pointcut expression="execution(* com.chen.test.Demo.demo1())" id="mypoint"/>

            <aop:after-throwing method="myexception"  pointcut-ref="mypoint" throwing="e1"/>

            </aop:aspect>

        </aop:config>

    <bean id="demo" class="com.chen.test.Demo"></bean>


    四 异常通知(Schema-based方式)

    1. 新建一个类,实现throwsAdvice接口,

    必须自己写方法,切必须叫afterThrowing

    有两个参数方式,必须是一个或者4个

    异常类型要与切点报的异常类型一致

    public class MyThrow implements ThrowsAdvice{

        public void afterThrowing(Exception ex) throws Throwable {

            System.out.println("执行异常通过-schema-base 方式");

        }

    }


    在applicationContext.xml 配置

    <bean id="mythrow"  class="com.chen.advice.MyThrow"></bean>

        <aop:config>

            <aop:pointcut expression="execution(* com.chen.test.Demo.demo1())" id="mypoint"/>

            <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint" />

        </aop:config>

    <bean id="demo" class="com.chen.test.Demo"></bean>


    五 环绕通知(Schema-based 方式)

    1. 把前置通知和后置通知都写到了一个通知里,组成那个了环绕通知

    2.实现步骤,新建一个类实现 MethodInterceptor

    public class MyArround implements MethodInterceptor {

        @Override

        public Object invoke(MethodInvocation arg0) throws Throwable {

            System.out.println("环绕-前置");

            Object result = arg0.proceed();//放行,调用切点方式

            System.out.println("环绕-后置");

            return result;

        }

    }


    配置 applicationContext.xml

    <bean id="myarround" class="com.chen.advice.MyArround"></bean>

        <aop:config>

        <aop:pointcut expression="execution(* com.chen.test.Demo.demo1())" id="mypoint"/>

        <aop:advisor advice-ref="myarround" pointcut-ref="mypoint" />

        </aop:config>

    <bean id="demo" class="com.chen.test.Demo"></bean>


    六 使用AspectJ 方式实现

    1. 新建类,不用实现

        1.1 类中方法名任意

    public class MyAdvice {

        public void mybefore(String name1,int age1){

           System.out.println("前置"+name1 );

        }

        public void mybefore1(String name1){

            System.out.println("前置:"+name1);

        }

        public void myaftering(){

            System.out.println("后置 2");

        }

        public void myafter(){

            System.out.println("后置 1");

        }

        public void mythrow(){

            System.out.println("异常");

        }

        public Object myarround(ProceedingJoinPoint p) throws Throwable{

            System.out.println("执行环绕");

            System.out.println("环绕-前置");

            Object result = p.proceed();

            System.out.println("环绕后置");

            return result;

    }


    1.2 配置spring 配置文件

    <aop: after> 后置通知,是否出现异常都执行

    <aop:after-returning/> 后置通知,只有切点正确执行时执行,

    <aop:after/> 和 <aop:after-returning/> 和 <aop: after-throwing/> 执行顺序和配置顺序相关

     execution() 括号不能扩上,args

    中间使用 and 不能使用 && 由 spring 把 and 解析成 &&

    args(名称) 名称自定义,顺序和demo1(参数,参数)对应

    <aop:before/> arg-name="名称" 名称来源于expression ="" 中args(),名称必须一样

    args() 有几个参数,arg-name 里面必须有几个参数

    arg-name="" 里面名称必须和通知方法参数名对象

    <aop:config>

        <aop:aspect ref="myadvice">

            <aop:pointcut expression="execution(* com.chen.test.Demo.demo1(String,int)) and args(name1,age1)" id="mypoint"/>

            <aop:pointcut expression="execution(* com.chen.test.Demo.demo1(String)) and args(name1)" id="mypoint1"/>

            <aop:before method="mybefore" pointcut-ref="mypoint" arg-names="name1,age1"/>

            <aop:before method="mybefore1" pointcut-ref="mypoint1" arg-names="name1"/>

        </aop:aspect>

    </aop:config>

    七 使用注解(基于 Aspect)

    1. spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解

    1.1 引入xmlns:context

    <context:component-scan base-package="com.chen.advice"></context:component-scan>

    2. @Component

        相当于<bean/>   

        如果没有参数,把类名首字母变小写,相当于<bean id=""/>

        @Component("自定义名称")

    实现步骤

        在spring配置文件中配置注解在哪些包中1.  然后多个包  用  ,  隔开

        在Demo 类中添加@Componet

        在方法中添加@Pointcut("")定义切点

    @Component

    public class Demo {

        @Pointcut("execution(*com.chen.test.Demo.demo1())")

        public void demo1() throws Exception{

            // int i = 5/0;

            System.out.println("demo1");

        }

    }


    3.3 在通知类中配置

        @Component 类被 Spring管理

        @Aspect 相当于<aop:aspect/> 表示通知方法在当前类中


    @Component

    @Aspect

    public class MyAdvice {

        @Before("com.chen.test.Demo.demo1()")

        public void mybefore(){

            System.out.println("前置");

        }

        @After("com.chen.test.Demo.demo1()")

        public void myafter(){

            System.out.println("后置通知");

        }

        @AfterThrowing("com.chen.test.Demo.demo1()")

        public void mythrow(){

            System.out.println("异常通知");

        }

        @Around("com.chen.test.Demo.demo1()")

        public Object myarround(ProceedingJoinPoint p) throws Throwable{

            System.out.println("环绕-前置");

            Object result = p.proceed();

            System.out.println("环绕-后置");

        return result;

        }

    }


    九 静态代理设计模式

    1.  由代理对象代理所有真实对象的功能

            自己编写代理类

            每个代理的功能需要单独编写

    2静态代理设计模式的缺点

            当代理功能比较多时,代理类中方法需要写很多

    十 动态代理

    1. 为了解决静态代理频繁编写代理功能缺点

    2 分类

            jdk 提供的

            cglib 动态代理

    十一  JDK 动态代理

    1. 和cglib 动态代理相比

            优点:jdk自带,不需要导入额外jar

            缺点  : 真实对象必须实现接口,利用反射机制,效率不高

    2. 使用JDK动态代理是可能出现下面异常

                出现原因:希望把接口对象转换为具体真实对象

    异常: java.lang.ClassCastException

    十二 cglib 动态代理

    1.cglib优点

            基于字节码,生成真实对象的子类

                运行效率高于JDK动态代理

            不需要实现接口

      2 cgilb 缺点

            非JDK功能,需要导入额外jar

    3. 使用spring aop时,只要出现Proxy 和真实对象转换异常

            设置为true 使用cglib

            设置为 false 使用 jdk(默认值)

    <aop: aspectj-autoproxyproxy-target-class="true"></aop:aspectj-autoproxy>

     

    相关文章

      网友评论

        本文标题:java-spring-2

        本文链接:https://www.haomeiwen.com/subject/snorqqtx.html