Spring框架汇总(大学生的天堂 & 码农的圣殿)

企业级开发框架

  • Spring Framework 是整个 Spring 生态的基础,各个模块都是基于 Spring Framework 衍生出来的。
  • Spring Boot 是一个快速开发框架,让开发者可以快速搭建一套基于 Spring 的应用程序,集成了 Spring 其他模块以及第三方模块,MyBatis、Hibernate 等,只需简单的配置就可以使用,开箱即用,默认支持 JSON 格式,实现前后端开发非常方便,Spring Boot + Vue。
  • Spring Cloud 是一套整合了分布式应用常用模块的框架,基于 Spring Boot。

  • Maven:软件管理工具

  • POM:Project Object Model,就是一个 XML 文件,配置 jar 依赖关系。

Spring要解决的问题

  • ① 解决依赖注入的问题,让使用者的代码能够完成解耦工作。
  • ② 依赖注入DI:
    • 一个类的对象,需要正常执行,首先需要把另外一个对象注入进来。
    • Spring的核心依然是依赖注入,Spring替我们完成了依赖注入,所以,对于使用者来说,我们在用的功能是叫控制反转(IOC)。
  • 控制反转IOC:
    • 为什么要IOC:如果存在大量的接口,需要实现类来完成注入工作。那么一旦需要修改实现类的时候,所有的这些被注入的实现类都需要通过修改源码的方式来进行修改。如果修改遗漏,或者检查起来都特别的麻烦。

Spring 应用程序

两个bean的级联

集合的注入

Spring继承

Spring依赖

P命名空间

IOC工厂方法

IOC自动装载

Ioc的开发方式

Aop


Spring 应用程序

1、Idea创建 Maven 工程。
2、pom.xml 中引入 Spring 依赖。
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.7.RELEASE</version>
  </dependency>
</dependencies>

Spring 的两大核心机制:IoC(控制反转) 和 AOP(面向切面编程)

IoC 对象创建不再由开发者完成,而是容器自动创建,开发者直接取出来用即可。

3、创建 applicationContext.xml

此 处 默 认 实 体 类 已 经 创 建 完 成。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="
	    http://www.springframework.org/schema/context
	    http://www.springframework.org/schema/context/spring-context.xsd
	    http://www.springframework.org/schema/beans
	    http://www.springframework.org/schema/beans/spring-beans.xsd
	    http://www.springframework.org/schema/tx
	    http://www.springframework.org/schema/tx/spring-tx.xsd
	    http://www.springframework.org/schema/jdbc
	    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
	    http://www.springframework.org/schema/cache
	    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd
	    http://www.springframework.org/schema/aop
	    http://www.springframework.org/schema/aop/spring-aop.xsd
	    http://www.springframework.org/schema/util
	    http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="stu" class="com.chenny.entity.Student" >
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="22"></property>
    </bean>

</beans>

XmlBeanFactory和ClassPathXmlApplicationContext的区别

  • XmlBeanFactory:
    • a. 延迟加载,在调用getBean的时候完成实例的创建
    • b. 带来的问题:在运行时会大量消耗资源,没有单例
  • ClassPathXmlApplicationContext
    • a. 默认是容器加载后,同时创建了所有的bean;默认是单例,即他的作用域是singleton;这个单例并不是真正意义上的单例,只是容器始终只创建这么一个bean的实例
    • b. 当作用域为prototype的时候,即bean被延迟加载
    • c. 面试很容易会被问到bean的默认情况,以及如何修改
Bean的作用域

在这里插入图片描述

  • 静态工厂
    • a. 静态工厂,不再是Spring来直接调用构造
    • b. 必须用懒加载,因为让Spring容器启动的时候,如果不是懒加载,那么他会去调用对应的构造!!!(既是工厂又是单例,推荐使用懒加载。)
    • c. 比方说,有些数据需要等到容器正式启动完,数据准备好以后,再获取bean的时候才能正常执行
    • d. 容器只创建了一次实例,可以通过设置作用域来指定是单例还是多例
4、加载 IoC 容器,获取创建好的 bean。
public class IoCTest {
    public static void main(String[] args) {
        //1.加载 IoC 容器,spring.xml
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        Student student = (Student) applicationContext.getBean("stu");
        System.out.println(student);
    }
}

特殊字符的处理方式。

<?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="stu" class="com.chenny.entity.Student" >
        <property name="id" value="1"></property>
<!--        <property name="name" value="&lt;张三&gt;"></property>-->
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="22"></property>
    </bean>

</beans>

使用 IoC 容器创建对象,实体类的注意事项:
  • 必须有无参构造函数。
  • 成员变量必须有 setter 方法。

IoC 实例化对象的过程,通过反射+XML解析的方式对 spring.xml 进行处理,反射拿到无参构造函数,调用创建对象,同时获取 setter 方法,调用完成成员变量的赋值。

获取 IoC bean 的方式

  • 通过 id 获取
Student student = (Student) applicationContext.getBean("stu");
  • 通过运行时类获取
Student student = applicationContext.getBean(Student.class);

通过运行时类获取 bean 存在一个弊端,当 spring.xml 中配置两个 Student 的 bean 时会抛出异常。


创建 IoC bean 的方式

  • 无参构造
<bean id="stu2" class="com.chenny.entity.Student">
  <property name="id" value="2"></property>
  <property name="name" value="李四"></property>
  <property name="age" value="23"></property>
</bean>
  • 有参构造

1、在实体类中创建有参构造。

public Student(Integer id, String name, Integer age) {
  this.id = id;
  this.name = name;
  this.age = age;
}

2、在 spring.xml 中进行配置。

<bean id="stu3" class="com.chenny.entity.Student">
  <constructor-arg index="1" value="王五"></constructor-arg>
  <constructor-arg index="0" value="1"></constructor-arg>
  <constructor-arg index="2" value="20"></constructor-arg>
</bean>
<bean id="stu3" class="com.chenny.entity.Student">
  <constructor-arg name="name" value="王五"></constructor-arg>
  <constructor-arg name="id" value="1"></constructor-arg>
  <constructor-arg name="age" value="20"></constructor-arg>
</bean>
<bean id="stu3" class="com.chenny.entity.Student">
  <constructor-arg value="1"></constructor-arg>
  <constructor-arg value="王五"></constructor-arg>
  <constructor-arg value="20"></constructor-arg>
</bean>
返回顶层

两个 bean 的级联

package com.chenny.entity;

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Classes classes;

    public Classes getClasses() {
        return classes;
    }

    public void setClasses(Classes classes) {
        this.classes = classes;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

    public Student(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Student() {
    }
}
package com.chenny.entity;

public class Classes {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Classes{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
<bean id="stu2" class="com.chenny.entity.Student">
  <property name="id" value="2"></property>
  <property name="name" value="李四"></property>
  <property name="age" value="23"></property>
  <property name="classes" ref="classes1"></property>
</bean>

<bean id="classes1" class="com.chenny.entity.Classes">
  <property name="id" value="1"></property>
  <property name="name" value="Java班"></property>
</bean>
返回顶层

Spring 继承

  • Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。
  • ⼦ bean 可以继承⽗ bean 的属性值。
Customer
package com.chenny.entity;

public class Customer {
    private int type;
    private String action;
    private String Country;
	//.....set,get,constructor
customer.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!--  abstract如果为true,你就不能实例化它了  -->
    <bean id="BaseCustomerMalaysia" class="com.chenny.entity.Customer" abstract="true">
        <property name="action" value="sell"></property>
        <property name="country" value="Malaysia" />
    </bean>

    <bean id="CustomerBean" parent="BaseCustomerMalaysia">
        <property name="action" value="buy" />
        <property name="type" value="1" />
    </bean>

</beans>
App
package com.chenny.test;

import com.chenny.entity.Customer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("customer.xml");
        Customer customer = (Customer) applicationContext.getBean("CustomerBean");
        System.out.println(customer);
    }
}

返回顶层

Spring 依赖

A 依赖于 B,则⼀定会先创建 B,再创建 A。

test.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean name="user" class="com.chenny.entity.User" depends-on="car">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
    </bean>

    <bean name="car" class="com.chenny.entity.Car">
        <property name="id" value="1"></property>
        <property name="brand" value="BWP"></property>
    </bean>
</beans>
User
package com.chenny.entity;

public class User {
    private Integer id;
    private String name;

    public User() {
        System.out.println("User创建了!");
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Car
package com.chenny.entity;

public class Car {
    private Integer id;
    private String brand;

    public Car() {
        System.out.println("Car创建了!");
    }

    public Car(Integer id, String brand) {
        this.id = id;
        this.brand = brand;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", brand='" + brand + '\'' +
                '}';
    }
}

DependsOnTest
package com.chenny.test;

import com.chenny.entity.Car;
import com.chenny.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DependsOnTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("test.xml");
        User user = (User) applicationContext.getBean("user");
        Car car = (Car) applicationContext.getBean("car");
    }
}

返回顶层

P命名空间

p 命名空间实际是通过调⽤成员变量的 setter ⽅法来完成赋值的,如果是 bean 之间的级联映射,需要调⽤ p:属性名-ref 来配置。

<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="world" class="com.chenny.World"/>
	
	<!-- 通过set方法注入的传统的bean定义 -->
	<bean id="hello1" class="com.chenny.Hello">
		<property name="p1" value="v1"/>
		<property name="p2" value="v2"/>
		<property name="world" ref="world"/>
	</bean>
	
	<!-- 通过set方法注入的使用p命名空间的bean定义 -->
	<bean id="hello2" class="com.chenny.Hello" p:p1="v1" p:p2="v2" p:world-ref="world"/>

</beans>
返回顶层

Spring IoC ⼯⼚⽅法

IoC 是典型的⼯⼚模式,如何使⽤⼯⼚模式创建 bean, IoC 通过⼯⼚模式创建 bean 有两种⽅式:

  1. 静态⼯⼚⽅法
  2. 实例⼯⼚⽅法

Car

package com.chenny.entity;

public class Car {
    private Integer id;
    private String brand;

    public Car() {
        System.out.println("Car创建了!");
    }

    public Car(Integer id, String brand) {
        this.id = id;
        this.brand = brand;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", brand='" + brand + '\'' +
                '}';
    }
}

静态⼯⼚⽅法

StaticFactory
package com.chenny.factory;

import com.chenny.entity.Car;

import java.util.HashMap;
import java.util.Map;

public class StaticFactory {
    public static Map<Integer, Car> cars;

    static {
        cars = new HashMap<Integer, Car>();
        cars.put(1,new Car(1,"奔驰"));
        cars.put(2,new Car(2,"宝马"));
        cars.put(3,new Car(3,"幻影"));
    }

    public static Map<Integer, Car> getCars() {
        return cars;
    }

    public static void setCars(Map<Integer, Car> cars) {
        StaticFactory.cars = cars;
    }

    public static Car getCar(Integer id){
        return cars.get(id);
    }
}

StaticFactoryTest
package com.chenny.test;

import com.chenny.entity.Car;
import com.chenny.factory.InstanceCarFactory;
import com.chenny.factory.StaticFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StaticFactoryTest {
    public static void main(String[] args) {

        /*Ioc方法*/
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("factory.xml");
        Car car = (Car) applicationContext.getBean("car");
        System.out.println(car);
        /*传统做法*/
        Car car = StaticFactory.getCar(1);
        System.out.println(car);
    }
}

返回本知识点头部

实例⼯⼚⽅法

InstanceCarFactory
package com.chenny.factory;

import com.chenny.entity.Car;

import java.util.HashMap;
import java.util.Map;

public class InstanceCarFactory {
    private Map<Integer, Car> carMap;

    public InstanceCarFactory() {
        carMap = new HashMap<Integer, Car>();
        carMap.put(1,new Car(1,"奔驰"));
        carMap.put(2,new Car(2,"宝马"));
        carMap.put(3,new Car(3,"幻影"));
    }
    public Car getCar(Integer id){
        return carMap.get(id);
    }
}

InstanceFactoryTest
package com.chenny.test;

import com.chenny.entity.Car;
import com.chenny.factory.InstanceCarFactory;
import com.chenny.factory.StaticFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class StaticFactoryTest {
    public static void main(String[] args) {
        /*传统做法*/
        InstanceCarFactory instanceCarFactory = new InstanceCarFactory();
        Car car1 = instanceCarFactory.getCar(1);
        System.out.println(car1);
        /*Ioc方法*/
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("factory.xml");
        Car car = (Car) applicationContext.getBean("car2");
        System.out.println(car);
    }
}

返回本知识点头部
返回顶层

Ioc自动装载

Spring框架提供了一种更加简便的方式:自动装载,不需要手动配置property,IOC容器会根据bean的配置自动选择bean完成依赖注入(DI)。

  • 自动装载有两种方式:
    • byName:通过属性名自动装载。
    • byType:通过属性对应的数据类型自动装载。
autowire.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
    创建person对象时,没有在property中配置car属性
    所以IOC容器会自动进行装载
    autowire="byName"表示通过匹配属性名的方式去装载对应的bean
    Person实体类中有car属性,所以就将的bean注入到person中。
-->
    <bean id="p1" class="com.test.entity.Person" autowire="byName"> 
        <property name="id" value="1"></property>
        <property name="name" value="ZhangSan"></property>
    </bean>

    <bean id="car1" class="com.test.entity.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="1"></constructor-arg>
    </bean>

    <!-- byType即通过属性的数据类型来配置。
                关键字:autowire="byType"
     -->
    <bean id="p2" class="com.test.entity.Person" autowire="byType"> 
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
    </bean>

    <bean id="car2" class="com.test.entity.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="1"></constructor-arg>
    </bean>

</beans>
Person
//先创建一个实体类,并且生成setter/getter方法和toString方法
public class Person {
    private int id;
    private String name;
    private Car car;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", car=" + car + "]";
    }

}
Car
package com.chenny.entity;

public class Car {
    private Integer id;
    private String brand;

    public Car() {
    }

    public Car(Integer id, String brand) {
        this.id = id;
        this.brand = brand;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    @Override
    public String toString() {
        return "Car{" +
                "id=" + id +
                ", brand='" + brand + '\'' +
                '}';
    }
}

注意
  1. 使用了byType进行自动装载,如果spring的配置文件中配置了两个Car的bean,但是IOC容器不知道应该将哪一个bean装载到person对象中,因此可能会报错。所以在使用byType进行自动装载时,spring的配置文件中只能配置一个Car的bean才能使用byType。
  2. 通过property标签手动进行属性的注入优先级更高,若自动注入和手动配置两种方式同时存在,则以property的配置为主。所以在日常的代码编写过程中,尽量避免的使用byType去自动装配。
返回顶层

基于注解的开发

IoC 的实现⽅式:基于 XML 配置⽂件、基于注解


基于xml的实现

在这里插入图片描述

controller
package com.chenny.controller;

import com.chenny.service.UserService;
import entity.User;

public class UserController {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public User findById(Integer id){
        return userService.findById(id);
    }
}

Service
package com.chenny.service.impl;

import com.chenny.reponsitory.UserReponsitory;
import com.chenny.service.UserService;
import entity.User;

public class UserServiceImpl implements UserService {
    private UserReponsitory userReponsitory;

    public void setUserReponsitory(UserReponsitory userReponsitory) {
        this.userReponsitory = userReponsitory;
    }

    @Override
    public User findById(Integer id) {
        return userReponsitory.findById(id);
    }
}

Reponsitory

package com.chenny.reponsitory.impl;

import com.chenny.reponsitory.UserReponsitory;
import entity.User;

import java.util.HashMap;
import java.util.Map;

public class UserReponsitoyImpl implements UserReponsitory {

    private static Map<Integer,User> userMap;

    public static void setUserMap(Map<Integer, User> userMap) {
        UserReponsitoyImpl.userMap = userMap;
    }

    static {
        userMap = new HashMap<Integer,User>();
        userMap.put(1,new User(1,"张三","123213"));
        userMap.put(2,new User(2,"李四","1232233"));
    }

    @Override
    public User findById(Integer id) {
        return userMap.get(id);
    }
}

spring.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="userController" class="com.chenny.controller.UserController">
        <property name="userService" ref="userService"></property>
    </bean>

    <bean id="userService" class="com.chenny.service.impl.UserServiceImpl">
        <property name="userRepository" ref="userRepository"></property>
    </bean>

    <bean id="userRepository" class="com.chenny.repository.impl.UserRepositoryImpl">

    </bean>
</beans>

基于注解的实现
  1. 创建 bean
  2. 完成 DI
  • 具体操作

    • 将 UserController、 UserService、 UserRepository 扫描到 IoC 容器中。
    • 在类中设置注解完成依赖注⼊。
  • @Controller

  • @Service

  • @Repository

  • @Resource

  • @Component

  • @Autowire:默认是通过 byType 完成⾃自动装载,如果要改为 byName,需要追加 @Qualifier,并注明⽬目标 bean 的 name。

Controller
package com.chenny.controller;

import com.chenny.service.UserService;
import entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;


@Controller("userController")
public class UserController {
    @Autowired
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public User findById(Integer id){
        return userService.findById(id);
    }
}

Service
package com.chenny.service.impl;

import com.chenny.reponsitory.UserReponsitory;
import com.chenny.service.UserService;
import entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserReponsitory userReponsitory;

    public void setUserReponsitory(UserReponsitory userReponsitory) {
        this.userReponsitory = userReponsitory;
    }

    @Override
    public User findById(Integer id) {
        return userReponsitory.findById(id);
    }
}

Reponsitory
package com.chenny.reponsitory.impl;

import com.chenny.reponsitory.UserReponsitory;
import entity.User;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.Map;

@Repository
public class UserReponsitoyImpl implements UserReponsitory {

    private static Map<Integer,User> userMap;

    public static void setUserMap(Map<Integer, User> userMap) {
        UserReponsitoyImpl.userMap = userMap;
    }

    static {
        userMap = new HashMap<Integer,User>();
        userMap.put(1,new User(1,"张三","123213"));
        userMap.put(2,new User(2,"李四","1232233"));
    }

    @Override
    public User findById(Integer id) {
        return userMap.get(id);
    }
}

Test
package com.chenny.test;

import com.chenny.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserController userController = (UserController) applicationContext.getBean("userController");
        System.out.println(userController.findById(1));
    }
}

spring.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:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
">

    <!-- 将类扫描到 IoC 容器中 -->
    <context:component-scan base-package="com.chenny"></context:component-scan>

</beans>
返回顶层

Spring AOP

Aspect Oriented Programming ⾯向切⾯编程, OOP ⾯向对象编程,将程序中所有参与模块都抽象成对象,然后通过对象之间的相互调⽤完成需求。


AOP 是 OOP 的⼀个补充,是在另外⼀个维度上抽象出对象,具体是指程序运⾏时动态地将⾮业务代码切⼊到业务代码中,从⽽实现代码的解耦合,将⾮业务代码抽象成⼀个对象,对该对象进⾏编程就是⾯向切⾯编程思想。


AOP的优点

  • ⼤⼤降低模块之间的耦合性
  • 提⾼代码的维护性
  • 提⾼代码的复⽤性
  • 集中管理⾮业务代码,便于维护
  • 业务代码不受⾮业务代码的影响,逻辑更加清晰
Cal
package com.chenny.aop;

public interface Cal {
    public int add(Integer numA,Integer numB);
    public int sub(Integer numA,Integer numB);
    public int mul(Integer numA,Integer numB);
    public int div(Integer numA,Integer numB);
}
CalImpl
package com.chenny.aop;

public class CalImpl implements Cal{
    @Override
    public int add(Integer numA, Integer numB) {
        int result = numA + numB;
        return result;
    }

    @Override
    public int sub(Integer numA, Integer numB) {
        int result = numA - numB;
        return result;
    }

    @Override
    public int mul(Integer numA, Integer numB) {
        int result = numA * numB;
        return result;
    }

    @Override
    public int div(Integer numA, Integer numB) {
        int result = numA / numB;
        return result;
    }
}

MyInvocationHandler
package com.chenny.aop;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class MyInvocationHandler implements InvocationHandler {

    private Object object = null;

    //返回代理对象
    public Object bind(Object object){
        this.object = object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName() + "参数是:" + Arrays.toString(args));
        Object result = method.invoke(this.object,args);
        System.out.println(method.getName() + "结果是:" + result);
        return result;
    }
}

CalTest
package com.chenny.test;

import com.chenny.aop.Cal;
import com.chenny.aop.CalImpl;
import com.chenny.aop.MyInvocationHandler;

public class CalTest {
    public static void main(String[] args) {
        Cal cal = new CalImpl();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Cal proxy = (Cal) myInvocationHandler.bind(cal);

        System.out.println(proxy.add(10,3));
        System.out.println(proxy.sub(10,3));
        System.out.println(proxy.div(10,3));
        System.out.println(proxy.mul(10,3));
    }
}


SpringAop

1、目标类

package com.chenny.aop;

public class CalImpl implements Cal {
    public int add(int num1, int num2) {
        int result = num1 + num2;
        return result;
    }

    public int sub(int num1, int num2) {
        int result = num1-num2;
        return result;
    }

    public int mul(int num1, int num2) {
        int result = num1*num2;
        return result;
    }

    public int div(int num1, int num2) {
        int result = num1/num2;
        return result;
    }
}

2、创建切面类 LoggerAspect

package com.chenny.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LoggerAspect {

    @Before(value = "execution(public int com.chenny.aop.CalImpl.*(..))")
    public void before(JoinPoint joinPoint){

        //获取方法名
        String name = joinPoint.getSignature().getName();
        //获取参数列表
        String atgs = Arrays.toString(joinPoint.getArgs());
        System.out.println(name + "参数列表是" + atgs);
    }

    @AfterReturning(value = "execution(public int com.chenny.aop.CalImpl.*(..))",returning = "result")
    public void afterReturning(JoinPoint joinPoint,Object result){
        System.out.println(joinPoint.getSignature().getName() + "结果为: "  +result);
    }

    @After(value = "execution(public int com.chenny.aop.CalImpl.*(..))")
    public void after(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + "业务代码执行完毕!");
    }

    @AfterThrowing(value = "execution(public int com.chenny.aop.CalImpl.*(..))",throwing ="e")
    public void afterThrowing (JoinPoint joinPoint,Exception e){
        System.out.println(joinPoint.getSignature().getName() + "方法抛出异常!" + e);
    }

}

3、将目标类和切面类交给 IoC 容器管理,IoC 容器会自动创建实例化对象,结合 JDK 动态代理,自动实现 InvocationHandler 接口,整合完成业务代码和非业务代码的解耦合。

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context.xsd
               http://www.springframework.org/schema/mvc
               http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.chenny"></context:component-scan>

    <!-- 为目标类自动生成代理对 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  • context:component-scan 将 com.southwind 包中的所有类扫描到 IoC 容器中,需要结合 @Component 注解完成。
  • aop:aspectj-autoproxy Spring 会结合切面类和目标类自动生成动态代理对象,代理对象完成非业务代码(日志打印)。

AOP 核心概念

  • 切面对象:根据切面抽象出来的对象,CalImpl 所有方法中需要加入日志的部分,抽象成一个切面对象 LoggerAspect。
  • 通知:切面对象的具体代码,即非业务代码,LoggerAspect 打印日志的各种操作。
  • 目标:被切割的对象,CalImpl。
  • 代理:切面对象,通知,目标混合之后的产物,Spring 通过 JDK 动态代理创建,真正执行代码的对象。
  • 连接点:需要被横切的位置,即通知要插入业务代码的具体位置。

同时给一个目标添加多个切面,执行顺序,实现 org.springframework.Ordered 接口,ordered 越小最先执行。

返回顶层

返回目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值