企业级开发框架

  • 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/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/jdbchttp://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsdhttp://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache-3.1.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/utilhttp://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.xmlApplicationContext 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;}@Overridepublic 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;}@Overridepublic 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/beanshttp://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;}@Overridepublic 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;}@Overridepublic 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/beanshttp://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;}@Overridepublic 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"表示通过匹配属性名的方式去装载对应的beanPerson实体类中有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;}@Overridepublic 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;}@Overridepublic 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的实现

  • 基于注解的实现


基于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;}@Overridepublic 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"));}@Overridepublic 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 {@Autowiredprivate 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 {@Autowiredprivate UserReponsitory userReponsitory;public void setUserReponsitory(UserReponsitory userReponsitory) {this.userReponsitory = userReponsitory;}@Overridepublic 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"));}@Overridepublic 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.xsdhttp://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{@Overridepublic int add(Integer numA, Integer numB) {int result = numA + numB;return result;}@Overridepublic int sub(Integer numA, Integer numB) {int result = numA - numB;return result;}@Overridepublic int mul(Integer numA, Integer numB) {int result = numA * numB;return result;}@Overridepublic 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);}@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://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 越小最先执行。

返回顶层


返回目录

Spring框架汇总(大学生的天堂 码农的圣殿)相关推荐

  1. 开发无框架单页面应用 — 老码农的祖传秘方

    什么是单页面应用(SPA)? 维基百科上的描述是这样的: JavaScript 1 2 3 "A single-page application (SPA), is a web applic ...

  2. Spring框架面试典籍30+ | 大别山码将

    Spring 什么是Spring框架 Spring 是⼀种轻量级(从大小与开销两方面)开发框架,目的是用于简化企业应用程序的开发,它使得开发者只需要 关心业务需求.常见的配置方式有三种:基于 XML ...

  3. 十个基于Python的BBS论坛类开源web框架汇总(附源码地址)

    1.LBForum LBForum是用django开发的论坛系统,LBForum主要注重部署的方便性和易用性,功能方面目前还比较简单. LBForum的开发尽量遵照Django可复用app原则,因此即 ...

  4. python web论坛_十个基于Python的BBS论坛类开源web框架汇总(附源码地址)

    1.LBForum LBForum是用django开发的论坛系统,LBForum主要注重部署的方便性和易用性,功能方面目前还比较简单. LBForum的开发尽量遵照Django可复用app原则,因此即 ...

  5. python论坛系统源码_十个基于Python的BBS论坛类开源web框架汇总(附源码地址

    1.LBForum LBForum是用django开发的论坛系统,LBForum主要注重部署的方便性和易用性,功能方面目前还比较简单. LBForum的开发尽量遵照Django可复用app原则,因此即 ...

  6. python bbs论坛_十个基于Python的BBS论坛类开源web框架汇总(附源码地址)

    1.LBForum LBForum是用django开发的论坛系统,LBForum主要注重部署的方便性和易用性,功能方面目前还比较简单. LBForum的开发尽量遵照Django可复用app原则,因此即 ...

  7. java毕业设计基于spring框架的论坛网站项目设计和源码

    一.主题 榴莲社区--java开发基于spring框架的论坛网站,基于spring框架的论坛网站项目设计和项目 源 码 免 费下 载 链 接 如 下:  毕业设计项目基于spring框架的论坛网站源码 ...

  8. spring cloud是什么时候流行的_老司机给我们解读 Spring Boot 最流行的 16 条实践 - 码农突围

    Spring Boot 是最流行的用于开发微服务的 Java 框架.在本文中,我将与你分享自 2016 年以来我在专业开发中使用 Spring Boot 所采用的最佳实践.这些内容是基于我的个人经验和 ...

  9. 2020年,大学生该如何成为一名初级码农

    文章目录 入学伊始 大一前期 加入工作室 大一末期 工作室是怎么样的 初入工作室 工作室培训 工作室换代 项目经验 项目开发对我的帮助 没有项目经验怎么办? 办法总是有的 回归主题 一点点建议.... ...

  10. 写给立志做程序员(码农)的大学生

    作者: 果冻虾仁  来源: CSDN  发布时间: 2017-08-10 23:08  阅读: 32769 次  推荐: 158   原文链接   [收藏] 写给立志做码农的大学生 确定方向 选择比努 ...

最新文章

  1. 剑指offer:面试题05. 替换空格
  2. redis Could not connect to Redis at 127.0.0.1:6379: Connection refused 问题解决
  3. 如何使用Git解决“错误:错误索引 - 致命:索引文件损坏”
  4. HDLBits答案(10)_D触发器、同步与异步复位、脉冲边沿检测
  5. vue项目做微信分享功能
  6. Truffle测试框架
  7. linux zip命令收藏
  8. windows配置caffe及matlab/python接口编译和调用(cpu/gpu)
  9. 汽车之家广告营销案例分析PPT模板
  10. 如何在springboot中返回jsp页面
  11. 关于京东商城在宜宾开通货到付款的随想
  12. 文件名称: 项目利用循环求和 、分数的累加、乘法表
  13. python in arcgis_终于晓得arcgis-python入门教程
  14. 产品经理如何进行数据分析?看这一篇文章就够了
  15. 从卷积神经网络(CNN)到图卷积神经网络(GCN)详解
  16. 格式化数据恢复怎么做?超实用的3种方法在这!
  17. 哈勃深空场以及星系合并的宇宙瑰丽景象
  18. ArcGIS 从DSM中提取高程点
  19. 苹果mac能安装计算机题库吗,如果苹果系统能安装在普通PC电脑上,你装么?
  20. 来,跟我一起 ,自研多端错误监控平台(完整版)

热门文章

  1. 杨百翰大学计算机科学专业,杨百翰大学计算机科学硕士.pdf
  2. aardio - 伪装进程测试
  3. bugku-秋名山老司机
  4. 2022华为机试真题 C++ 实现【数大雁】
  5. list数组遍历时能不能使用remove()方法,要注意什么
  6. 爬虫练习——爬取2020kpl王者荣耀职业联赛
  7. Spring MVC 详解
  8. asp.net配置web.config显示详细错误信息
  9. java二维码生成工具,可直接用于生产
  10. Paddle进阶实战系列(二):智慧交通预测系统