企业级开发框架
- 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="<张三>"></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 有两种⽅式:
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 + '\'' +
'}';
}
}
注意
- 使用了byType进行自动装载,如果spring的配置文件中配置了两个Car的bean,但是IOC容器不知道应该将哪一个bean装载到person对象中,因此可能会报错。所以在使用byType进行自动装载时,spring的配置文件中只能配置一个Car的bean才能使用byType。
- 通过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>
基于注解的实现
- 创建 bean
- 完成 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 越小最先执行。