ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring 自学笔记

2020-12-21 09:32:25  阅读:171  来源: 互联网

标签:执行 .. Spring 笔记 切面 自学 execution 方法 public


Spring 自学笔记2

文章目录

目录

1.6 自动注入 byName byType

引用类型的自动注入: spring框架根据某些规则可以给引用类型赋值。不用你在给引用类型赋值了
使用的规则常用的是byName, byType.
1.byName(按名称注入) : java类中引用类型的属性名和spring容器中(配置文件)的id名称一样,
且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。

<!-- 
语法:
         <bean id="xx" class="yyy" autowire="byName">
            简单类型属性赋值
         </bean>
-->
  <!--byName-->
    <bean id="myStudent" class="com.bjpowernode.ba04.Student"  autowire="byName">
        <property name="name" value="李四" />
        <property name="age" value="26" />
        <!--引用类型-->
        <!--<property name="school" ref="mySchool" />-->
    </bean>

    <!--声明School对象-->
    <bean id="school" class="com.bjpowernode.ba04.School">
        <property name="name" value="清华大学"/>
        <property name="address" value="北京的海淀区" />
    </bean>

2.byType(按类型注入) : java类中引用类型的数据类型和spring容器中(配置文件)的class属性
是同源关系的,这样的bean能够赋值给引用类型
同源就是一类的意思:
1.java类中引用类型的数据类型和bean的class的值是一样的。
2.java类中引用类型的数据类型和bean的class的值父子类关系的。
3.java类中引用类型的数据类型和bean的class的值接口和实现类关系的

<!--
语法:
         <bean id="xx" class="yyy" autowire="byType">
            简单类型属性赋值
         </bean>

 注意:在byType中, 在xml配置文件中声明bean只能有一个符合条件的,
              多余一个是错误的
-->
<!--byType-->
    <bean id="myStudent" class="com.bjpowernode.ba05.Student"  autowire="byType">
        <property name="name" value="张飒" />
        <property name="age" value="26" />
        <!--引用类型-->
        <!--<property name="school" ref="mySchool" />-->
    </bean>

    <!--声明School对象-->
    <bean id="mySchool" class="com.bjpowernode.ba05.School">
        <property name="name" value="人民大学"/>
        <property name="address" value="北京的海淀区" />
    </bean>

    <!--声明School的子类-->
    <!--<bean id="primarySchool" class="com.bjpowernode.ba05.PrimarySchool">
        <property name="name" value="北京小学" />
        <property name="address" value="北京的大兴区" />
    </bean>-->

6 基于注解的DI

通过注解完成java对象创建,属性赋值。

6.1 使用步骤

1.加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖。
使用注解必须使用spring-aop依赖

2.在类中加入spring的注解(多个不同功能的注解)

3.在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置

学习的注解:
1.@Component
2.@Respotory
3.@Service
4.@Controller
5.@Value
6.@Autowired
7.@Resource

ch04-di-anno: 通过spring的注解完成java对象的创建,属性。代替xml文件实现步骤:1.加入依赖2.创建类,在类中加入注解3.创建spring的配置文件 声明组件扫描器的标签,指名注解在你的项目的中的位置。4.使用注解创建对象, 创建容器ApplicationContext

给类创建对象

/**
 * @Component: 创建对象的, 等同于<bean>的功能
 *     属性:value 就是对象的名称,也就是bean的id值,
 *          value的值是唯一的,创建的对象在整个spring容器中就一个
 *     位置:在类的上面
 *
 *  @Component(value = "myStudent")等同于
 *   <bean id="myStudent" class="com.bjpowernode.ba01.Student" />
 *
 *  spring中和@Component功能一致,创建对象的注解还有:
 *  1.@Repository(用在持久层类的上面) : 放在dao的实现类上面,
 *               表示创建dao对象,dao对象是能访问数据库的。
 *  2.@Service(用在业务层类的上面):放在service的实现类上面,
 *              创建service对象,service对象是做业务处理,可以有事务等功能的。
 *  3.@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,
 *              控制器对象,能够接受用户提交的参数,显示请求的处理结果。
 *  以上三个注解的使用语法和@Component一样的。 都能创建对象,但是这三个注解还有额外的功能。
 *  @Repository,@Service,@Controller是给项目的对象分层的。
 */
//使用value属性,指定对象名称
//@Component(value = "myStudent")

//省略value
@Component("myStudent")

//不指定对象名称,由spring提供默认名称: 类名的首字母小写
//@Component
public class Student {
}

配置组件扫描器

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--声明组件扫描器(component-scan),组件就是java对象
        base-package:指定注解在你的项目中的包名。
        component-scan工作方式: spring会扫描遍历base-package指定的包,
           把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。

       加入了component-scan标签,配置文件的变化:
        1.加入一个新的约束文件spring-context.xsd
        2.给这个新的约束文件起个命名空间的名称
    -->
    <context:component-scan base-package="com.bjpowernode.ba02" />

   <!--
     <bean id="myXueXiao" class="com.bjpowernode.ba03.School">
        <property name="name" value="清华大学" />
        <property name="address" value="北京" />
    </bean>
    -->

    <!--加载属性配置文件-->
    <context:property-placeholder location="classpath:test.properties" />

</beans>

扫描多个包的方式

在这里插入图片描述

1.6.2 简单型属性value 赋值

@Component("myStudent")
public class Student {

    /**
     * @Value: 简单类型的属性赋值
     *   属性: value 是String类型的,表示简单类型的属性值
     *   位置: 1.在属性定义的上面,无需set方法,推荐使用。
     *         2.在set方法的上面
     */
    @Value("李四" )
    private String name;
    @Value("30")
    private Integer age;

6.2 引用类型Autowired

/**
     * 引用类型 byType
     * @Autowired: spring框架提供的注解,实现引用类型的赋值。
     * spring中通过注解给引用类型赋值,使用的是自动注入原理 ,支持byName, byType
     * @Autowired:默认使用的是byType自动注入。
     *   属性:required ,是一个boolean类型的,默认true (建议true)
     *       required=true:表示引用类型赋值失败,程序报错,并终止执行。
     *       required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null
     *
     *  位置:1)在属性定义的上面,无需set方法, 推荐使用
     *       2)在set方法的上面
     */
    @Autowired
    private School school;

     
    /*  如果要使用byName方式,需要做的是:
     *  1.在属性上面加入@Autowired
     *  2.在属性上面加入@Qualifier(value="bean的id") :表示使用指定名称的bean完成赋值。
     */

    //byName自动注入
    @Autowired
    @Qualifier("mySchool") //找名字
    private School school;

6.3 引用类型 Resource

/** 
     * 引用类型
     * @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值
     *            使用的也是自动注入原理,支持byName, byType .默认是byName
     *  位置: 1.在属性定义的上面,无需set方法,推荐使用。
     *        2.在set方法的上面
     *
     * @Resource只使用byName方式,需要增加一个属性 name
     * name的值是bean的id(名称)
     */
    //只使用byName
    @Resource(name = "mySchool")
     private School school;

7 AOP面像切面编程

AOP(Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程

序运行过程。

AOP 底层,就是采用动态代理模式实现的。采用了两种代理:JDK 的动态代理,与 CGLIB

的动态代理。

7.1 JDK、CGLIB动态代理

1.动态代理
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口

cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。
子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

2.动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离。
在这里插入图片描述

public class MyIncationHandler implements InvocationHandler {

    //目标对象
    private Object target; //SomeServiceImpl类

    public MyIncationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过代理对象执行方法时,会调用执行这个invoke()
        System.out.println("执行MyIncationHandler中的invoke()");
        System.out.println("method名称:"+method.getName());
        String methodName = method.getName();
        Object res = null;

        if("doSome".equals(methodName)){ //JoinPoint  Pointcut
            ServiceTools.doLog(); //在目标方法之前,输出时间
            //执行目标类的方法,通过Method类实现
            res  = method.invoke(target,args); //SomeServiceImpl.doSome()
            ServiceTools.doTrans(); //在目标方法执行之后,提交事务
        } else {
            res  = method.invoke(target,args); //SomeServiceImpl.doOther()
        }

        //目标方法的执行结果
        return res;
    }
}
 public static void main(String[] args) {
        //调用doSome, doOther
//        SomeService service = new SomeServiceImpl();
//        service.doSome();
//        System.out.println("============================================");
//        service.doOther();

        //使用jdk的Proxy创建代理对象
        //创建目标对象
        SomeService target = new SomeServiceImpl();

        //创建InvocationHandler对象
        InvocationHandler handler = new MyIncationHandler(target);

        //使用Proxy创建代理
        SomeService proxy = (SomeService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),handler);
        //com.sun.proxy.$Proxy0
        System.out.println("proxy======"+proxy.getClass().getName());
        //通过代理执行方法,会调用handler中的invoke()
        proxy.doSome();
        System.out.println("==================================================");
        proxy.doOther();
        }

1.7.2 aop 术语和实现框架

  1. Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
    Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,
    让开发人员用一种统一的方式,使用动态代理。
  2. AOP(Aspect Orient Programming)面向切面编程
    Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
    切面的特点: 一般都是非业务方法,独立使用的。
    Orient:面向, 对着。
    Programming:编程
  3. oop: 面向对象编程
    怎么理解面向切面编程 ?
    1)需要在分析项目功能时,找出切面。
    2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
    3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能
  4. 术语:
    1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,
    常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。
    2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
    3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
    4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
    5)Advice:通知,通知表示切面功能执行的时间。
    说一个切面有三个关键的要素:
    1)切面的功能代码,切面干什么
    2)切面的执行位置,使用Pointcut表示切面执行的位置
    3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。

5.aop的实现

aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。
spring主要在事务处理时使用aop。
我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。

7.2 Aspect 切面

切面(Aspect)
切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面
是通知(Advice)。实际就是对主业务逻辑的一种增强。

对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向
切面编程。然而,AspectJ 也实现了 AOP 的功能,且其实现方式更为简捷,使用更为方便,
而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框
架中。
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。

2.aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使用xml的配置文件 : 配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。

学习aspectj框架的使用。
1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After

表示切面执行的位置,使用的是切入点表达式。

​ com.service.impl
​ com.bjpowrnode.service.impl
​ cn.crm.bjpowernode.service

execution(* …service..*(…))

7.3 Aspectj 框架切入点表达式

[外在这里插入图片描述

AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是:
execution(modifiers-pattern? ret-type-pattern 
declaring-type-pattern?name-pattern(param-pattern)
 throws-pattern?)
解释例如:
modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选的部分
以上表达式共 4 个部分。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
重要:
execution(public * *(..)) 
指定切入点为:任意公共方法。
execution(* set*(..)) 
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service.*.*(..)) 
指定切入点为:定义在 service 包里的任意类的任意方法。
execution(* com.xyz.service..*.*(..))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后
面必须跟“*”,表示包、子包下的所有类。
execution(* *..service.*.*(..))
举例:
execution(public * *(..)) 
指定切入点为:任意公共方法。
execution(* set*(..)) 
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service.*.*(..)) 
指定切入点为:定义在 service 包里的任意类的任意方法。
execution(* com.xyz.service..*.*(..))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“..”出现在类名中时,后
面必须跟“*”,表示包、子包下的所有类。
execution(* *..service.*.*(..))
指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点
execution(* *.service.*.*(..))
指定只有一级包下的 serivce 子包下所有类(接口)中所有方法为切入点
execution(* *.ISomeService.*(..))
指定只有一级包下的 ISomeSerivce 接口中所有方法为切入点
execution(* *..ISomeService.*(..))
指定所有包下的 ISomeSerivce 接口中所有方法为切入点
execution(* com.xyz.service.IAccountService.*(..)) 
指定切入点为:IAccountService 接口中的任意方法。
execution(* com.xyz.service.IAccountService+.*(..)) 
指定切入点为:IAccountService 若为接口,则为接口中的任意方法及其所有实现类中的任意
方法;若为类,则为该类及其子类中的任意方法。
execution(* joke(String,int)))
指定切入点为:所有的 joke(String,int)方法,且 joke()方法的第一个参数是 String,第二个参
数是 int。如果方法中的参数类型是 java.lang 包下的类,可以直接使用类名,否则必须使用
全限定类名,如 joke( java.util.List, int)。
execution(* joke(String,*))) 
指定切入点为:所有的 joke()方法,该方法第一个参数为 String,第二个参数可以是任意类
型,如joke(String s1,String s2)和joke(String s1,double d2)都是,但joke(String s1,double d2,String 
s3)不是。
execution(* joke(String,..))) 
指定切入点为:所有的 joke()方法,该方法第一个参数为 String,后面可以有任意个参数且
参数类型不限,如 joke(String s1)、joke(String s1,String s2)和 joke(String s1,double d2,String s3)
都是。
execution(* joke(Object))
指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型。joke(Object ob)
是,但,joke(String s)与 joke(User u)均不是。
execution(* joke(Object+))) 
指定切入点为:所有的 joke()方法,方法拥有一个参数,且参数是 Object 类型或该类的子类。
不仅 joke(Object ob)是,joke(String s)和 joke(User u)也是。

7.4 创建切面类和配置文件 与多种写法

  1. 使用aspectj实现aop的基本步骤:
    1.新建maven项目
    2.加入依赖
    1)spring依赖
    2)aspectj依赖
    3)junit单元测试
    3.创建目标类:接口和他的实现类。
    要做的是给类中的方法增加功能
  2. 创建切面类:普通类
    1)在类的上面加入 @Aspect
    2)在类中定义方法, 方法就是切面要执行的功能代码
    在方法的上面加入aspectj中的通知注解,例如@Before
    有需要指定切入点表达式execution()
  3. 创建spring的配置文件:声明对象,把对象交给容器统一管理
    声明对象你可以使用注解或者xml配置文件
    1)声明目标对象
    2)声明切面类对象
    3)声明aspectj框架中的自动代理生成器标签。
    自动代理生成器:用来完成代理对象的自动创建功能的。
  4. 创建测试类,从spring容器中获取目标对象(实际就是代理对象)。
    通过代理执行方法,实现aop的功能增强。
<dependency>  <!-- 加入依赖-->
<groupId>org.springframework</groupId> 
<artifactId>spring-aspects</artifactId> 
<version>5.2.5.RELEASE</version>
</dependency>
    <!--把对象交给spring容器,由spring容器统一创建,管理对象-->
    <!--声明目标对象-->
    <bean id="someService" class="com.bjpowernode.ba08.SomeServiceImpl" />

    <!--声明切面类对象-->
    <bean id="myAspect" class="com.bjpowernode.ba08.MyAspect" />

    <!--声明自动代理生成器:使用aspectj框架内部的功能,创建目标对象的代理对象。
        创建代理对象是在内存中实现的, 修改目标对象的内存中的结构。 创建为代理对象
        所以目标对象就是被修改后的代理对象.

        aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。
    -->
    <!--<aop:aspectj-autoproxy />-->


    <!--
       如果你期望目标类有接口,使用cglib代理
       proxy-target-class="true":告诉框架,要使用cglib动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
/**
 *  @Aspect : 是aspectj框架中的注解。
 *     作用:表示当前类是切面类。
 *     切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
 *     位置:在类定义的上面
 */
@Aspect
public class MyAspect {
    /**
     * 定义方法,方法是实现切面功能的。
     * 方法的定义要求:
     * 1.公共方法 public
     * 2.方法没有返回值
     * 3.方法名称自定义
     * 4.方法可以有参数,也可以没有参数。
     *   如果有参数,参数不是自定义的,有几个参数类型可以使用。
     */


    /**
     * @Before: 前置通知注解
     *   属性:value ,是切入点表达式,表示切面的功能执行的位置。
     *   位置:在方法的上面
     * 特点:
     *  1.在目标方法之前先执行的
     *  2.不会改变目标方法的执行结果
     *  3.不会影响目标方法的执行。
     */
   /* @Before(value = "execution(public void com.bjpowernode.ba01.SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(){
        //就是你切面要执行的功能代码
        System.out.println("前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/


    /*@Before(value = "execution(void com.bjpowernode.ba01.SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(){
        //就是你切面要执行的功能代码
        System.out.println("1=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/

  /*  @Before(value = "execution(void *..SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(){
        //就是你切面要执行的功能代码
        System.out.println("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/

    /*@Before(value = "execution(* *..SomeServiceImpl.*(..))")
    public void myBefore(){
        //就是你切面要执行的功能代码
        System.out.println("3=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/

    /*@Before(value = "execution(* do*(..))")
    public void myBefore2(){
        //就是你切面要执行的功能代码
        System.out.println("4=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/


    /*@Before(value = "execution(* com.bjpowernode.ba01.*ServiceImpl.*(..))")
    public void myBefore2(){
        //就是你切面要执行的功能代码
        System.out.println("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }*/


    
}

测试类
   @Test
    public void test01(){
        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ctx.getBean("someService");

        //com.sun.proxy.$Proxy8 :jdk动态代理
        //com.sun.proxy.$Proxy0
        System.out.println("proxy:"+proxy.getClass().getName());
        //通过代理的对象执行方法,实现目标方法执行时,增强了功能
        proxy.doSome("lisi",20);
    }

在这里插入图片描述

7.5 JoinPoint 连接点 与前置通知 Before

连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。

/**
     * 指定通知方法中的参数 : JoinPoint
     * JoinPoint:业务方法,要加入切面功能的业务方法
     *    作用是:可以在通知方法中获取方法执行时的信息, 例如方法名称,方法的实参。
     *    如果你的切面功能中需要用到方法的信息,就加入JoinPoint.
     *    这个JoinPoint参数的值是由框架赋予, 必须是第一个位置的参数
     */
    @Before(value = "execution(void *..SomeServiceImpl.doSome(String,Integer))")
    public void myBefore(JoinPoint jp){
        //获取方法的完整定义
        System.out.println("方法的签名(定义)="+jp.getSignature());
        System.out.println("方法的名称="+jp.getSignature().getName());
        //获取方法的实参
        Object args [] = jp.getArgs();
        for (Object arg:args){
            System.out.println("参数="+arg);
        }
        //就是你切面要执行的功能代码
        System.out.println("2=====前置通知, 切面功能:在目标方法之前输出执行时间:"+ new Date());
    }

7.6 注解通知

7.6.1 @AfterReturning 后置通知
/**
     * 后置通知定义方法,方法是实现切面功能的。
     * 方法的定义要求:
     * 1.公共方法 public
     * 2.方法没有返回值
     * 3.方法名称自定义
     * 4.方法有参数的,推荐是Object ,参数名自定义
     */

    /**
     * @AfterReturning:后置通知
     *    属性:1.value 切入点表达式
     *         2.returning 自定义的变量,表示目标方法的返回值的。
     *          自定义变量名必须和通知方法的形参名一样。
     *    位置:在方法定义的上面
     * 特点:
     *  1。在目标方法之后执行的。
     *  2. 能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
     *      Object res = doOther();
     *  3. 可以修改这个返回值
     *
     *  后置通知的执行
     *    Object res = doOther();
     *    参数传递: 传值, 传引用
     *    myAfterReturing(res);
     *    System.out.println("res="+res)
     *
     */
    @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",
                    returning = "res")
    public void myAfterReturing(  JoinPoint jp  ,Object res ){
        // Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
        System.out.println("后置通知:方法的定义"+ jp.getSignature());
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
        if(res.equals("abcd")){
            //做一些功能
        } else{
            //做其它功能
        }

        //修改目标方法的返回值, 看一下是否会影响 最后的方法调用结果 测试后会!!
        if( res != null){
            res = "Hello Aspectj";
        }

    }
7.6.2 @Around 环绕通知
/**
     * 环绕通知方法的定义格式
     *  1.public
     *  2.必须有一个返回值,推荐使用Object
     *  3.方法名称自定义
     *  4.方法有参数,固定的参数 ProceedingJoinPoint
     */

    /**
     * @Around: 环绕通知
     *    属性:value 切入点表达式
     *    位置:在方法的定义什么
     * 特点:
     *   1.它是功能最强的通知
     *   2.在目标方法的前和后都能增强功能。
     *   3.控制目标方法是否被调用执行
     *   4.修改原来的目标方法的执行结果。 影响最后的调用结果
     *
     *  环绕通知,等同于jdk动态代理的,InvocationHandler接口
     *
     *  参数:  ProceedingJoinPoint 就等同于 Method
     *         作用:执行目标方法的
     *  返回值: 就是目标方法的执行结果,可以被修改。
     *
     *  环绕通知: 经常做事务, 在目标方法之前开启事务,执行目标方法, 在目标方法之后提交事务
     */
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {

        String name = "";
        //获取第一个参数值
        Object args [] = pjp.getArgs();
        if( args!= null && args.length > 1){
              Object arg=  args[0];
              name =(String)arg;
        }

        //实现环绕通知
        Object result = null;
        System.out.println("环绕通知:在目标方法之前,输出时间:"+ new Date());
        //1.目标方法调用
        if( "zhangsan".equals(name)){
            //符合条件,调用目标方法
            result = pjp.proceed(); //method.invoke(); Object result = doFirst();

        }

        System.out.println("环绕通知:在目标方法之后,提交事务");
        //2.在目标方法的前或者后加入功能

        //修改目标方法的执行结果, 影响方法最后的调用结果
        if( result != null){
              result = "Hello AspectJ AOP";
        }

        //返回目标方法的执行结果
        return result;
    }
7.6.3 @AfterThrowing 异常通知-注解中有throwing属性
/**
     * 异常通知方法的定义格式
     *  1.public
     *  2.没有返回值
     *  3.方法名称自定义
     *  4.方法有个一个Exception, 如果还有是JoinPoint,
     */

    /**
     * @AfterThrowing:异常通知
     *     属性:1. value 切入点表达式
     *          2. throwinng 自定义的变量,表示目标方法抛出的异常对象。
     *             变量名必须和方法的参数名一样
     * 特点:
     *   1. 在目标方法抛出异常时执行的
     *   2. 可以做异常的监控程序, 监控目标方法执行时是不是有异常。
     *      如果有异常,可以发送邮件,短信进行通知
     *
     *  执行就是:
     *   try{
     *       SomeServiceImpl.doSecond(..)
     *   }catch(Exception e){
     *       myAfterThrowing(e);
     *   }
     */
    @AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))",
            throwing = "ex")
    public void myAfterThrowing(Exception ex) {
        System.out.println("异常通知:方法发生异常时,执行:"+ex.getMessage());
        //发送邮件,短信,通知开发人员
    }

7.6.4 @After 最终通知

/**
     * 最终通知方法的定义格式
     *  1.public
     *  2.没有返回值
     *  3.方法名称自定义
     *  4.方法没有参数,  如果还有是JoinPoint,
     */

    /**
     * @After :最终通知
     *    属性: value 切入点表达式
     *    位置: 在方法的上面
     * 特点:
     *  1.总是会执行
     *  2.在目标方法之后执行的
     *
     *  try{
     *      SomeServiceImpl.doThird(..)
     *  }catch(Exception e){
     *
     *  }finally{
     *      myAfter()
     *  }
     *
     */
    @After(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public  void  myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般做资源清除工作的。
     }
7.6.4 @Pointcut 定义切入点 (不是通知注解,是个辅助功能的注解)
/**
     * @Pointcut: 定义和管理切入点, 如果你的项目中有多个切入点表达式是重复的,可以复用的。
     *            可以使用@Pointcut
     *    属性:value 切入点表达式
     *    位置:在自定义的方法上面
     * 特点:
     *   当使用@Pointcut定义在一个方法的上面 ,此时这个方法的名称就是切入点表达式的别名。
     *   其它的通知中,value属性就可以使用这个方法名称,代替切入点表达式了
     */
    @Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))" )
    private void mypt(){
        //无需代码,
    }
 @After(value = "mypt()") //定义名字 
 ///@After(value = "execution(* *..SomeServiceImpl.doThird(..))")
    public  void  myAfter(){
        System.out.println("执行最终通知,总是会被执行的代码");
        //一般做资源清除工作的。
     }

    @Before(value = "mypt()")
    public  void  myBefore(){
        System.out.println("前置通知,在目标方法之前先执行的");
    }

7.6.5 cglib 动态代理

当目标类没有接口时, com.bjpowernode.ba07.SomeServiceImpl$$EnhancerBySpringCGLIB$$575c8b90 用的是继承方式

//目标类
public class SomeServiceImpl {

    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }


}
//测试类
 @Test
    public void test01(){
        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeServiceImpl proxy = (SomeServiceImpl) ctx.getBean("someService");


        /**
         * 目标类没有接口,使用cglib动态代理, spring框架会自动应用cglib
         * com.bjpowernode.ba07.SomeServiceImpl$$EnhancerBySpringCGLIB$$575c8b90
         */
        System.out.println("proxy:"+proxy.getClass().getName());
        //通过代理的对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();
        }

有接口也可以使用 cglib 动态代理,spring 配置文件 applicationContext.xml 加上下面那句就可以了

<!--
       如果你期望目标类有接口,使用cglib代理
       proxy-target-class="true":告诉框架,要使用cglib动态代理
    -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
//目标类
public class SomeServiceImpl implements SomeService {
@Override
    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }
}

//测试类
    @Test
    public void test01(){
        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ctx.getBean("someService");


        System.out.println("proxy:"+proxy.getClass().getName());
        //输出 com.bjpowernode.ba07.SomeServiceImpl$$EnhancerBySpringCGLIB$$575c8b90
        //通过代理的对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();

8 Druid 连接池

,使用cglib动态代理, spring框架会自动应用cglib
* com.bjpowernode.ba07.SomeServiceImpl E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIB575c8b90
*/
System.out.println(“proxy:”+proxy.getClass().getName());
//通过代理的对象执行方法,实现目标方法执行时,增强了功能
proxy.doThird();
}


有接口也可以使用 cglib 动态代理,spring 配置文件 applicationContext.xml 加上下面那句就可以了

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

```java
//目标类
public class SomeServiceImpl implements SomeService {
@Override
    public void doThird() {
        System.out.println("执行业务方法doThird()");
    }
}

//测试类
    @Test
    public void test01(){
        String config="applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        //从容器中获取目标对象
        SomeService proxy = (SomeService) ctx.getBean("someService");


        System.out.println("proxy:"+proxy.getClass().getName());
        //输出 com.bjpowernode.ba07.SomeServiceImpl$$EnhancerBySpringCGLIB$$575c8b90
        //通过代理的对象执行方法,实现目标方法执行时,增强了功能
        proxy.doThird();

后续Druid 阿里数据源连接池的介绍…

标签:执行,..,Spring,笔记,切面,自学,execution,方法,public
来源: https://blog.csdn.net/AJunAmzing/article/details/111466971

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有