其他分享
首页 > 其他分享> > Spring Aop,Spring Bean,Spring XML

Spring Aop,Spring Bean,Spring XML

作者:互联网

Spring AOP

前置知识

AOP(Aspect Oriented Programming):面向切面编程,是Spring 早期版本的核心功能,负责管理对象生命周期与对象装配。为了实现对象的管理和装配,一个自然而然的想法就是,加一个中间层代理(字节码增强)来实现所有对象的托管。

IoC(Inversion of Control):控制反转。也称为DI(Dependency Injection) 依赖注入。

对象装配思路的改进:
从对象A 直接引用和操作对象B,变成对象A 里指需要依赖一个接口IB,系统启动和装配阶段,把IB 接口的实例对象注入到对象A,这样A 就不需要依赖一个IB 接口的具体实现,也就是类B。从而可以实现在不修改代码的情况,修改配置文件,即可以运行时替换成注入IB 接口另一实现类C的一个对象实例。

依赖问题:
属性依赖可以解决。A属性里面用到了B,B的属性里面用到了A。创建A对象的时候发现A的属性里需要一个B对象,那么就会创建一个B对象将其塞到A对象中去。创建B对象的时候发现B的属性里需要A,就把A塞到B对象里。
构造器依赖不可以解决。A的构造器里面用到了B,B的构造器里面用到了A不能解决。创建A的时候,发现A对象需要用到B对象;创建B对象的时候,发现B对象需要A对象。

@Autowired和@Resource

//@Autowired按bean的类型注入
//@Autowired(required = false);懒加载,等到Class被使用的时候才开始进行注入
//所以不会在程序启动时就开始检查
 @Autowired(required = true)

//@Resource按bean的Id进行注入
@Resource(name = "student100")

使用AOP

xml配置AOP

被代理的接口InterfaceSchool

package io.simon.aop;

/**
 * 被代理的接口
 */
public interface InterfaceSchool {
  /**
   * 铃声ding
   */
  void ding();
}

该接口有一个实现类School

package io.simon.aop;

public class School implements InterfaceSchool {

  @Override
  public void ding() {
    System.out.println("ding ....... 上课了");
  }
}

假设需要在ding方法上做增强,定义一个AOP

package io.simon.aop;

import org.aspectj.lang.ProceedingJoinPoint;

public class Aop1 {

  //前置通知
  public void start() {
    System.out.println("====>begin ding... ");
  }

  //后置通知
  public void end() {
    System.out.println("====>finish ding... ");
  }

  //环绕通知
  public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("====>around begin ding");

    //调用process()方法才会真正的执行实际被代理的方法
    joinPoint.proceed();

    System.out.println("====>around finish ding");
  }
}

用xml配置AOP

<?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/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 定义一个School类的Bean -->
    <bean id="school1" class="io.simon.aop.School"/>

 	<!-- 定义一个Aop1类的Bean -->
    <bean id="aop1" class="io.simon.aop.Aop1"/>

    <aop:config>
    	<!-- 配置Aop的切点 -->
    	<!-- expression="execution(* io.simon.aop.InterfaceSchool.*(..))"
    	表示要执行io.simon.aop.InterfaceSchool类下面的所有方法-->
        <aop:pointcut id="p1" expression="execution(* io.simon.aop.InterfaceSchool.*(..))"/>

        <aop:aspect ref="aop1">
            <aop:around method="around" pointcut-ref="p1"/>
            <aop:before method="start" pointcut-ref="p1"/>
            <aop:after method="end" pointcut-ref="p1"/>
        </aop:aspect>
    </aop:config>
</beans>

测试

package io.simon;

import io.simon.aop.InterfaceSchool;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("simonApplicationContext.xml");

    InterfaceSchool school1 = context.getBean(InterfaceSchool.class);
    school1.ding();
  }
}

打印输出结果
在这里插入图片描述

注解配置AOP

被代理的接口InterfaceSchool

package io.simon.aop;

/**
 * 被代理的接口
 */
public interface InterfaceSchool {
  /**
   * 铃声ding
   */
  void ding();
}

该接口有一个实现类School

package io.simon.aop;

public class School implements InterfaceSchool {

  @Override
  public void ding() {
    System.out.println("ding ....... 上课了");
  }
}

InterfaceSchool接口的ding方法上做增强。定义的AOP如下。

package io.simon.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect//将整个类声明为一个切面
public class Aop2 {
 //将point()方法声明为一个切面,切在io.simon.aop.InterfaceSchool类的所有方法上面
  @Pointcut(value = "execution(* io.simon.aop.InterfaceSchool.*(..))")
  public void point() {

  }

  @Before(value = "point()")//将before方法绑定到point这个切面上
  public void before() {
    System.out.println("====>begin ding... ");
  }
  
  //将after方法绑定到point这个切面上
  @AfterReturning(value = "point()")//AfterReturning方法在point方法return以后执行
  public void before() {
  public void end() {
    System.out.println("====>finish ding... ");
  }
  //将around方法绑定到point这个切面上
  @Around("point()")//around方法环绕着point方法执行,在before方法前,在after方法后
  public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("====>around begin ding");
    joinPoint.proceed();
    System.out.println("====>around finish ding");
  }
}

xml中只需要bean相关的配置并开启AOP的注解支持

<?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/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            https://www.springframework.org/schema/aop/spring-aop.xsd">
    

    <!-- 定义一个School类的Bean -->
    <bean id="school2" class="io.simon.aop.School"/>

    <bean id="aop2" class="io.simon.aop.Aop2"/>

    <!-- Enables the use of the @AspectJ style of Spring AOP -->
    <aop:aspectj-autoproxy/>
</beans>

测试

package io.simon;

import io.simon.aop.InterfaceSchool;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("simonApplicationContext.xml");

    InterfaceSchool school2 = context.getBean(InterfaceSchool.class);
    school2.ding();
  }
}

运行结果
在这里插入图片描述

Spring Bean

Bean的整个加载过程
在这里插入图片描述
需要查看详细的代码,可以重点关注
org.springframework.beans.factory.support包下AbstractAutowireCapableBeanFactory类的
doCreateBeaninstantiateBean方法。

关于Bean的配置,我们通常使用xml和注解这两种方式来进行配置。

使用xml来配置Bean

由于需要通过Setter方法来注入值,因此Student类中Setter方法是必须的,Getter方法可以不要。

Student类

package spring.beans;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data//自动生成Getter和Setter方法,还会生成ToString方法
public class Student {

  private String name;
  private String id;
  private String school;
  
}

在resources文件夹下新建applicationContext.xml配置文件

D:\dev\Java\java-traning\spring-learning>tree
卷 Data 的文件夹 PATH 列表
卷序列号为 5665-4A88
D:.
├─.idea
│  └─inspectionProfiles
├─src
│  ├─main
│  │  ├─java
│  │  │  └─spring
│  │  │      ├─aop
│  │  │      └─beans
│  │  └─resources
│  └─test
│      └─java
└─target
    ├─classes
    │  └─spring
    │      └─beans
    └─generated-sources
        └─annotations

applicationContext.xml中配置bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student01" class="spring.beans.Student">
        <property name="name" value="张三"/>
        <property name="id" value="20171060001"/>
        <property name="school" value="北京大学"/>
    </bean>

</beans>

测试类,从ClassPathXmlApplicationContext中取出bean。

package spring.beans;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Student student = (Student) context.getBean("student01");
    System.out.println(student.toString());
  }
}

image-20210220151540795

使用注解配置Bean

方法一:使用@Bean显示声明

Student类

package spring.beans;

import lombok.Data;

@AllArgsConstructor//有参构造方法是必需的
@ToString
public class Student {

  private String name;
  private String id;
  private String school;

}

Student的配置类。

带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。
@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。

package spring.beans;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StudentConf {

  @Bean(name = "student02")
  public Student student() {
    return new Student("李四", "20171060002", "清华大学");
  }
}

测试类:AnnotationConfigApplicationContext指定含有bean的package。

package spring.beans;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
  public static void main(String[] args) {
    ApplicationContext context = new AnnotationConfigApplicationContext("spring.beans");
    Student student = (Student) context.getBean("student02");
    System.out.println(student.toString());
  }
}

image-20210220153615065

方法二:不使用@Bean显示声明

Student类如下:

使用@Component@Service@Controller@Repository都能隐式地创建Bean。Student类中不需要有参构造方法,Setter方法也不需要。无参构造方法是默认就有的。

package spring.beans;

import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

@ToString
@Component
//@Service
//@Controller
//@Repository
public class Student {

  @Value("王五")
  private String name;

  @Value("20171060003")
  private String id;

  @Value("南京大学")
  private String school;
}

测试类

package spring.beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
  public static void main(String[] args) {;
    ApplicationContext context = new AnnotationConfigApplicationContext("spring.beans");
    Student student = context.getBean(Student.class);
    System.out.println(student.toString());
  }
}

image-20210220162635414

Spring XML配置原理

在xml的文件头部,会有很多链接,这些链接是xml文件的命名空间,规定了我们能在该文件中配置的内容。
在这里插入图片描述
所有的jar包里也会带上.xsd这个文件
在这里插入图片描述
在spring.schemas这个文件里指明了xsd位于jar包中的哪一个路径。
在这里插入图片描述
在xml中进行配置时,会出现提示,提示了我们能配置的属性,这便是xsd文件的作用。
在这里插入图片描述
如下内容便是spring-beans.xsd文件中所定义的一小部分。
在这里插入图片描述
xml中定义的Bean怎么转化为一个Bean的定义呢?这是根据spring.handles中指定的转换规则来进行转化的。
在这里插入图片描述
在spring.handles中对应的几个java类中,实现了读取xml的DOM节点,将其拼装为一个Bean的定义。然后再执行Spring Bean从创建到销毁的这整个流程。
在这里插入图片描述
总结起来,XML配置的整个流程如下:
在这里插入图片描述
而从Spring 2.5开始,就开始逐渐支持注解方式的配置,到现在注解的配置已经成为了主流方式。
在这里插入图片描述

标签:XML,ding,Spring,springframework,Bean,context,org,import,public
来源: https://blog.csdn.net/qq_42799615/article/details/113796722