栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring框架的基本使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring框架的基本使用

目录

简要说明:

实例说明:ioc

实例说明:基于注解的IOC实现技术DI

拓展知识

在三层架构的项目中使用注解

 拓展知识

AOP 面向切面编程

AspectJ框架

AspectJ 中常用的通知有四种类型:

前置通知实现@Before :

后置通知@AfterReturning

环绕通知@Around

最终通知@After

自定义切入点别名@Pointcut(了解)

常用通知的集合执行顺序说明


简要说明:

Spring框架:它是一个容器.它是整合其它框架的框架。

Spring框架特点:

轻量级 :由20多个模块构成并且体积很小

面向接口编程:使用接口,就是面向灵活,项目的可扩展性,可维护性都极高.接口不关心实现类的类型.使用时接口指向实现类,切换实现类即可切换整个功能.

(核心)IOC(Inversion of Control)控制反转:是把传统上由程序代码直接操控的对象(自己创建new的对象)的调用权交给容器,通过容器实现对象的创建,属性赋值, 依赖的管理。

(核心)面向切面编程(AOP):就是将公共的,通用的,重复的代码单独开发,在需要的时候反织回去.底层的原理是动态代理.

实例说明:ioc

1.创建一个maven项目

在pom.xml文件中添加spring依赖



      org.springframework
      spring-context
      5.3.19

2.在/com/dy/s1包下定义一个实体类School

public class School {
    private String name;
    private String address;
    //为了给成员变量注入值,必须提供无参构造方法和setXXX()方法
    public void setAddress(String address) {
        this.address = address;
    }
    public void setName(String name) {
        this.name = name;
    }
    public School() {
        System.out.println("学校的无参的构造方法被调用..........");
    }
    @Override
    public String toString() {
        return "School{" +
                "name='" + name + ''' +
                ", address='" + address + ''' +
                '}';
    }
}

在/com/dy/s1包下定义一个实体类Student 

public class Student {
    private String name;
    private int age;
    private School school;//引用类型的成员变量,学生所在的学校
    public Student() {
        System.out.println("学生的无参的构造方法..........");
    }
  //交给Spring容器注入值,必须提供setXXX()方法
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSchool(School school) {
        this.school = school;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}

3.在resources包下创建Spring的配置文件applicationContext.xml

bean 实例在调用无参构造器创建对象后,就要对 bean 对象的属性进行初始化。初始化是由容器自动完成的,称为注入。根据注入方式的不同,常用的有两类:set 注入、构造注入。

方法一:使用setter注入(注入分为简单类型注入和引用类型注入)
简单类型注入值:使用value属性

引用类型注入值:使用ref属性 (当指定 bean(Student )的某属性值(school)为另一bean 的实例(school)时,通过 ref 指定它们间的引用关系。ref 的值必须为某 bean 的 id 值。)

必须要注意:使用setter注入必须提供无参的构造方法,必须提供setXXX()方法.




   
    
           
          
    
    
    
       
           
          
        
    
    
        
        
    
    
    
        
        
        
    
    
    
        
        
        
    

创建方法二的测试类

public class Mytest2 {
@Test   //通过有参构造的名字入值
public void testSchool(){
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  School school = (School) ac.getBean("school");
  System.out.println(school);
 }
//测试结果:School{name='清华大学', address='海淀区'}
@Test  //通过有参构造的下标入值
public void testStudent(){
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  Student stu = (Student) ac.getBean("stu");
  System.out.println(stu);
 }
//测试结果:Student{name='钱七', age=22, school=School{name='清华大学', address='海淀区'}}
@Test  //使用默认的构造方法的参数顺序
public void testStudentSequence(){
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  Student stu = (Student) ac.getBean("stuSequence");
  System.out.println(stu);
 }
}
//测试结果:Student{name='陈十', age=22, school=School{name='清华大学', address='海淀区'}}

实例说明:基于注解的IOC实现技术DI

DI (Dependency Injection)依赖注入:对于 DI 使用注解,将不再需要在 Spring 配置文件中声明bean实例。Spring 中使用注解, 需要在原有 Spring 运行环境基础上再做一些改变。需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。

关于对象中注解的说明:创建对象的常用注解
@Component:可以创建任意对象.创建的对象的默认名称是类名的驼峰命名法.也可以指定对象的名称@Component("指定名称").
@Controller:专门用来创建控制器的对象(Servlet),这种对象可以接收用户的请求,可以返回处理结果给客户端.
@Service:专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完毕后的结果返回给界面层.
@Repository:专门用来创建数据访问层的对象,负责数据库中的增删改查所有操作.

1.创建一个maven项目(并在pom.xml文件中添加Spring依赖)

2.在/com/dy/s1包下创建实体类Student

//@Component:可以创建任意对象.创建的对象的默认名称是类名的驼峰命名法.
//也可以指定对象的名称@Component("指定名称") ,指定名称后,就只能用这个名称
//@Value:用来给简单类型注入值(8种基本类型+String)
@Component
//@Component("stu") 指定名称后,就只能用这个名称
public class Student {
    @Value("张三")   //使用Value注入时,不管后面是什么类型都必须带""号
    private String name;
    @Value("20")
    private int age;

  public Student() {
        System.out.println("学生对象的无参构造方法.........");
    }

  @Override
  public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

 3.在配置文件resources包下创建Spring的配置文件applicationContext.xml

基于注解的IOC,必须要在Spring的核心配置文件中添加包扫描.



    
    
    

4.创建测试类

public class MyTest01 {
  @Test
  public void testStudent(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    Student student = (Student) ac.getBean("student");
//Student student = (Student) ac.getBean("stu"); 注解如果使用了指定名称,这里也必须是指定的名称
    System.out.println(student);
    }
}
测试结果结果:
学生对象的无参构造方法.........
Student{name='张三', age=20}

拓展知识

1.引用类型的注入

@Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入.

@Autowired
@Qualifier("名称"):使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入.

例:

创建父类School

//@Component  未规定名称 此时School对象的名称就是school
@Component("schoolFu")  //规定了名称
public class School {  
    @Value("清华大学")
    private String name;
    @Value("海淀区")
    private String address;

    public School() {
        System.out.println("School的无参的构造方法.........");
    }
    @Override
    public String toString() {
        return "School{" +
                "name='" + name + ''' +
                ", address='" + address + ''' +
                '}';
    }
}

创建子类SubSchool

//@Component 此时School对象的名称就是school
@Component("schoolZi")  //规定了名称
public class SubSchool extends School {
    @Value("清华附小")
    private String name;
    @Value("海淀小区")
    private String address;

    public SubSchool() {
        System.out.println("这是SubSchool子类的构造方法......");
    }

    @Override
    public String toString() {
        return "SubSchool{" +
                "name='" + name + ''' +
                ", address='" + address + ''' +
                '}';
    }
}

创建学生类 Student并引用School

@Component
public class Student {
    @Value("李四")
    private String name;
    @Value("23")
    private int age;

    //@Autowired  按引用类型按类型注入
    @Autowired
    @Qualifier("schoolZi")  //使用规定名称注入
    private School school;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}

applicationContext.xml配置包扫描



测试类 

public class MyTest03 {
@Test
  public void testStudent(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    Student stu = (Student) ac.getBean("student");
    System.out.println(stu);
    }
}

情况一:在父子类中的注解@Component中未注明名称,在测试类中Student中的school按引用类型注入时  测试结果是:(默认为父类优先注入)

School的无参的构造方法.........
School的无参的构造方法.........
这是SubSchool子类的构造方法......
Student{name='李四', age=23, school=School{name='清华大学', address='海淀区'}}

情况二:在父子类中父类注解@Component中规定了名称,子类没有,在测试类中Student中的school按引用类型注入时  测试结果是:(优先父类,但如果父类对象名称对不上,就进行第二次筛选,选中与被注入对象相同名称的对象进行注入)

School的无参的构造方法.........
School的无参的构造方法.........
这是SubSchool子类的构造方法......
Student{name='李四', age=23, school=SubSchool{name='清华附小', address='海淀小区'}}

注意:在有父子类的情况下,使用按类型注入,就意味着有多个可注入的对象.此时按照名称进行二次筛选,选中与被注入对象相同名称的对象进行注入. 

情况三:在父子类中的注解@Component分别规定了不同的名称,在测试类中Student中的school类型也引用了规定名称注入时  测试结果是:

School的无参的构造方法.........
School的无参的构造方法.........
这是SubSchool子类的构造方法......
Student{name='李四', age=23, school=SubSchool{name='清华附小', address='海淀小区'}}

在三层架构的项目中使用注解

创建项目并在pom.xml文件中添加Spring依赖

1.创建实体类(com.dy.pojo包下)

public class Users {
    private int uid;
    private String uname;
    private int uage;

    public int getUid() {return uid;}
    public void setUid(int uid) { this.uid = uid; }

    public String getUname() { return uname; }
    public void setUname(String uname) { this.uname = uname; }

    public int getUage() { return uage; }
    public void setUage(int uage) { this.uage = uage;}

    public Users(int uid, String uname, int uage) {
        this.uid = uid;
        this.uname = uname;
        this.uage = uage;
    }
    public Users() {}

    @Override
    public String toString() {
        return "Users{" +
                "uid=" + uid +
                ", uname='" + uname + ''' +
                ", uage=" + uage +
                '}';
    }
}

2.创建数据访问层 的实现类和接口(com.dy.mapper包下)

@Repository  //交给spring框架去创建数据访问层的对象
public class UsersMapperImpl implements UsersMappr {
    @Override
    public int insert(Users u) {
        System.out.println(u.getUname()+"用户增加成功!");
        return 1;
    }
}
public interface UsersMappr {
    int insert(Users u ); //增加用户
}

3. 创建业务逻辑层的接口和实现类(com.dy.service包下)

public interface UsersService {
    //增加用户
    int insert(Users users);
}
@Service  //交给spring创建业务逻辑层的对象
public class UsersServiceImpl implements UsersService {
    //切记切记:在所有的业务逻辑层中都必定有数据访问层的对象
    @Autowired
    private UsersMappr usersMappr;
    @Override
    public int insert(Users users) {
        return usersMappr.insert(users);
    }
}

4.创建界面层的实现类(com.dy.controller包下)

@Controller  //spring来创建控制器的对象(Servlet)
public class UsersController {
    //如何去访问业务逻辑层,就是创建对象
    //切记切记:所有的界面层都会有业务逻辑层的对象
    @Autowired
    public UsersService usersService ;
    //界成层的功能实现,对外提供访问的功能
    public int insert(Users users){
        return usersService.insert(users);
    }
}

 5.配置applicationContext.xml(基于注解的配置需要扫描包)



    
    
    
    

6.创建测试类 

public class MyTest {
@Test
  public void testInsertUsers(){
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  UsersController usersController = (UsersController) ac.getBean("uController");
  //测试功能
  int num = usersController.insert(new Users(200,"王五",24));
  System.out.println(num);
    }
}
测试结果:
王五用户增加成功
1

 拓展知识

1.添加包扫描的方式:单个包扫描(推荐使用)

当项目中有多个包需要被添加扫描时,可以单个配置包扫描

例:(单个添加)


也可以只添加一个包扫描,多个包之间以逗号或空格或分号分隔

例:(多个添加)

2.为应用指定多个 Spring 配置文件(当项目越来越大,需要多人合作开发,只有一个配置文件(或所有的都配置在一个文件中)的话就存在很大隐患.这时我们就需要对配置进行合理的拆分)

例:项目下实体类Users、实体类Book的三层架构xml配置拆分

按层拆分:(按其中的架构类型进行拆分)(界面层,业务逻辑层,数据访问层)

applicationContext_controller.xml 对应界面层


applicationContext_service.xml 对应业务逻辑层


applicationContext_mapper.xml 对应数据访问层 


按功能拆分:(按实体类功能进行拆分)

applicationContext_users.xml



applicationContext_book.xml  



3.当按层拆分后的配置文件,我们需要对这些文件单独配置一个文件(区别大的名字.xml)进行整合
单个文件导入 :



批量导入:

AOP 面向切面编程

AOP(Aspect Orient Programming),面向切面编程。
切面:公共的,通用的,重复的功能称为切面,面向切面编程就是将切面提取出来,单独开发,在需要调用的方法中通过动态代理的方式进行织入.

Spring支持AOP的编程,常用的有以下几种:
Before通知:在目标方法被调用前调用,涉及接口org.springframework.aop.MethodBeforeAdvice; 
After通知:在目标方法被调用后调用,涉及接口org.springframework.aop.AfterReturningAdvice; 
Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.ThrowsAdvice; 
Around通知:拦截对目标对象方法调用,涉及接口org.aopalliance.intercept.MethodInterceptor;

AOP常用的术语:
切面(Aspect):就是那些重复的,公共的,通用的功能称为切面,例如:日志,事务,权限.
连接点(JoinPoint):就是目标方法.因为在目标方法中要实现目标方法的功能和切面功能.
切入点(Pointcut):指定切入的位置,多个连接点构成切入点.切入点可以是一个目标方法,可以是一个类中的所有方法,可以是某个包下的所有类中的方法.
目标对象(Target):操作谁,谁就是目标对象.
通知(Advice):来指定切入的时机.是在目标方法执行前还是执行后还是出错时,还是环绕目标方法切入切面功能.

AspectJ框架

AspectJ 的切入点表达式:(重点)

规范的公式:execution(访问权限 方法返回值 方法声明(参数) 异常类型)
简化后的公式:execution( 方法返回值 方法声明(参数) )

用到的符号:
*   代表任意个任意的字符(通配符)
..  如果出现在方法的参数中,则代表任意参数
..  如果出现在路径中,则代表本路径及其所有的子路径

示例:指定切入点
execution(public * *(..)):任意(public)公共方法。
execution(* set*(..)):任何一个以“set”开始的方法。
execution(* com.xyz.service.impl.*.*(..)):任意的返回值类型,在指定包下的任意类(这里是.*必须是类,因为方法不能出现在包中)的任意方法的任意参数。
execution(* com.xyz.service..*.*(..)):任意的返回值类型 ,在指定的service及其子包下的任意类的任意方法的任意参数。com.xyz.service.a.b.*.*(..)  com.xyz.service.*.*(..)
execution(* *..service.*.*(..)):指定所有包下的 serivce 子包下的类(接口)中所有方法。
execution(* *.service.*.*(..)):指定只有一个包下的 serivce 子包下的类(接口)中所有方法。

AspectJ 中常用的通知有四种类型:

前置通知实现@Before :

在目标方法执行前切入切面功能.在切面方法中不可以获得目标方法的返回值,只能得到目标方法的签名.

实现步骤:

1.添加依赖 需要添加spring和aspectj的依赖



   org.springframework
   spring-context
   5.3.19



   org.springframework
   spring-aspects
   5.3.19

2.创建业务接口

public interface SomeService {
    String doSome(String name,int age); //方法1
    void show(); //无类型无参数的方法2
}

3.创建业务实现类

@Service
public class SomeServiceImpl implements SomeService {
  @Override
  public String doSome(String name, int age) {
    System.out.println("doSome的业务功能实现................");
    return "abcd";
    }
  @Override
  public void show() {
    System.out.println("show的业务方法实现.............");
   }
}

4.创建切面类,实现切面方法 类中定义了若干普通方法,将作为不同的通知方法,用来增强功能。

@Aspect  //交给AspectJ的框架去识别切面类
@Component  
public class MyAspect {  
//切面类中包含各种的切面方法,所有切面的功能都是由切面方法来实现的,可以将各种切面都在此类中进行开发
  @Before(value = "execution( * com.dy.s1.*.*(..))")
  public void myBefore(JoinPoint jp){
//JoinPoint类型参数在目标方法执行之前执行,该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。
    System.out.println("切面方法中的前置通知功能实现............");
    System.out.println("目标方法的签名:"+jp.getSignature());
    System.out.println("目标方法的参数:"+ Arrays.toString(jp.getArgs()));
  }
}

5.在applicationContext.xml文件中进行切面绑定




6.测试类

public class MyTest {
 @Test
 public void test(){
   //创建容器并启动
   ApplicationContext ac = new ClassPathXmlApplicationContext("s1/applicationContext.xml");
   //取出代理对象
   //默认是JDK动态代理,取时必须使用接口类型,使用接口来接,永远不出错.
   SomeService someService = (SomeService) ac.getBean("someServiceImpl");
   //输出代理对象
   System.out.println(someService.getClass());
   String s = someService.doSome("张三", 20);
   System.out.println("返回值:"+s);
   someService.show();
    }
}
测试结果:
class jdk.proxy2.$Proxy16

切面方法中的前置通知功能实现............
目标方法的签名:String com.dy.s1.SomeService.doSome(String,int)
目标方法的参数:[张三, 20]
doSome的业务功能实现................
返回值:abcd   //前置通知是无法改变目标方法的返回值的

切面方法中的前置通知功能实现............
目标方法的签名:void com.dy.s1.SomeService.show()
目标方法的参数:[]
show的业务方法实现执行.............

后置通知@AfterReturning

在目标方法执行之后执行,由于是目标方法之后执行,所以可以获取到目标方法的返回值,如果目标方法的返回值是简单类型(8种基本类型+String)则不可改变.如果目标方法的返回值是引用类型则可以改变。

实现步骤:

1.添加依赖 需要添加spring和aspectj的依赖(和上方的一样)

2.创建业务接口

public interface SomeService {
  String doSome(String name,int age);
  Student change();
}

3.创建实体类

public class Student {
    private String name;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
}

4.创建业务实现类 

@Service
public class SomeServiceImpl implements SomeService {
  @Override
  public String doSome(String name, int age) {
    System.out.println("doSome()业务方法被执行............");
    return "abcd";
    }
  @Override
  public Student change() {
    System.out.println("change()方法被执行............");
    return new Student("张三");
    }
}

 5.创建切面类,实现切面方法

@Aspect
@Component
public class MyAspect {
   //returning:指定目标方法的返回值的名称,此名称必须与切面方法的参数名称一致.
  @AfterReturning(value = "execution(* com.dy.s2.*.*(..))",returning = "obj")
  public void myAfterReturning(Object obj){
    System.out.println("后置通知功能实现..............");
    if(obj != null){ //判断返回值不为空
        if(obj instanceof String){  //判断返回值是否是String类型
            obj = obj.toString().toUpperCase();  //将返回值全部大写
            System.out.println("在切面方法中目标方法的返回值:"+obj);
            }
        if(obj instanceof Student){ //判断返回值类型是否是Student类型
            Student stu = (Student) obj;  //是就进行类型强转
            stu.setName("李四");  //修改返回值
            System.out.println("在切面方法中目标方法的返回值:"+stu);
            }
        }
    }
}

6.在applicationContext.xml文件中进行切面绑定(和上方的一样)

7.测试类

public class MyTest {
 @Test
 public void test(){
   //创建容器并启动
   ApplicationContext ac = new ClassPathXmlApplicationContext("s2/applicationContext.xml");
   //取出代理对象
   SomeService someService = (SomeService) ac.getBean("someServiceImpl");
   String s = someService.doSome("张三",22);
   System.out.println("在测试方法中目标方法的返回值:"+s);
        
   Student stu = someService.change();
   System.out.println("在测试为中目标方法的返回值是:"+stu);
  }   
}
测试结果:
doSome()业务方法被执行............
后置通知功能实现..............
在切面方法中目标方法的返回值:ABCD 
在测试方法中目标方法的返回值:abcd //基本类型修改失败

change()方法被执行............
后置通知功能实现..............
在切面方法中目标方法的返回值:Student{name='李四'}
在测试为中目标方法的返回值是:Student{name='李四'} //引用类型修改成功

环绕通知@Around

通过拦截目标方法的方式 ,在目标方法前后增强功能的通知.它是功能最强大的通知,一般事务使用此通知.它可以轻易的改变目标方法的返回值.

 实现步骤:

1.添加依赖 需要添加spring和aspectj的依赖(和上方的一样)

2.创建业务接口

public interface SomeService {
  String doSome(String name,int age);
}

3.创建业务实现类 

@Service
public class SomeServiceImpl implements SomeService{
  @Override
  public String doSome(String name, int age) {
    System.out.println("doSome业务方法被执行...."+name);
    return "abcd";
  }
}

4.创建切面类,实现切面方法

@Aspect
@Component
public class MyAspect {
  @Around(value = "execution(* com.dy.s3.*.*(..))")
  //必须要回避异常Throwable
  public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
  //前切功能实现
  System.out.println("环绕通知中的前置功能实现............");
  //目标方法调用
  Object obj = pjp.proceed(pjp.getArgs());
  //后切功能实现
  System.out.println("环绕通知中的后置功能实现............");
  return obj.toString().toUpperCase();  //改变了目标方法的返回值
    }
}

5.测试类

public class MyTest03 {
  @Test
  public void test01(){
   //创建容器并启动
   ApplicationContext ac = new ClassPathXmlApplicationContext("s3/applicationContext.xml");
   //取出代理对象
   SomeService someService = (SomeService) ac.getBean("someServiceImpl");
   String s = someService.doSome("张三",22);
   System.out.println("在测试方法中目标方法的返回值:"+s);
   }
}
测试结果:
环绕通知中的前置功能实现............
doSome业务方法被执行....张三
环绕通知中的后置功能实现............
在测试方法中目标方法的返回值:ABCD

最终通知@After

无论目标方法是否正常执行,最终通知的代码都会被执行.(可参考下面集合说明)

自定义切入点别名@Pointcut(了解)

如果多个切面切入到同一个切入点,可以使用别名简化开发.(可参考下面集合说明)

@Pointcut(value = "execution(* com.dy.s4.*.*(..))")
    public void mycut(){}

常用通知的集合执行顺序说明

 实现步骤:

1.添加依赖 需要添加spring和aspectj的依赖(和上方的一样)

2.创建业务接口

public interface SomeService {
    String doSome(String name, int age);
}

3.创建业务实现类 

@Service
public class SomeServiceImpl implements SomeService {
  @Override
  public String doSome(String name, int age) {
    System.out.println("doSome业务方法被执行...."+name);
    return "abcd";
    }
}

4.创建切面类,实现切面方法

@Aspect
@Component
public class MyAspect {
    @After(value = "mycut()")
    public void myAfter(){
        System.out.println("最终通知的功能........");
    }
    @Before(value = "mycut()")
    public void myBefore(){
        System.out.println("前置通知的功能........");
    }
    @AfterReturning(value = "mycut()",returning = "obj")
    public void myAfterReturning(Object obj){
        System.out.println("后置通知的功能........");
    }
    @Around(value = "mycut()")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕通知中的前置通知的功能........");
        Object obj = pjp.proceed(pjp.getArgs());
        System.out.println("环绕通知中的后置通知的功能........");
        return obj;
    }
    @Pointcut(value = "execution(* com.dy.s4.*.*(..))")
    public void mycut(){}
}

5.测试类

public class MyTest04 {
 @Test
 public void test01(){
   ApplicationContext ac = new ClassPathXmlApplicationContext("s4/applicationContext.xml");
   SomeService someService = (SomeService) ac.getBean("someServiceImpl");
   String s = someService.doSome("张三",22);
   System.out.println("在测试方法中目标方法的返回值:"+s);
    }
}
测试结果:
环绕通知中的前置通知的功能........
前置通知的功能........
doSome业务方法被执行....张三
后置通知的功能........
最终通知的功能........
环绕通知中的后置通知的功能........
在测试方法中目标方法的返回值:abcd

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/888132.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号