SSM

java-spring-2

2018-11-27  本文已影响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>

 

上一篇下一篇

猜你喜欢

热点阅读