什么是Spring
概念:是一款开源轻量级应用程序框架 主要用企业级的构建程序,解决复杂性的业务问题,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理。
作用:提高开发效率,降低代码的耦合度,提高代码的复用性,提高代码的键状性
谈谈Spring的两个核心模块
ioc的概念:控制反转 是一种设计思想 将你设计好的对象交给容器控制
ioc控制反转:将创建好的对象交给容器进行管理,自动组装,管理事务,整合Mybatis
aop的概念: AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
aop面向切面:在不修改原代码的情况下对业务进行增强。
DI:依赖注入
理解:DI实际上就是ioc的具体实现
可以把ioc的容器中的资源进行使用
表现形式 setter注入,构造函数注入, 注解注入
为什么要使用Spring
1.方便解耦,简化开发 依赖到组件松耦合
2.AOP编程的支持 面向切面 通知类 通知 切面 连接点
3. IOC管理对象和组件 xml和注解方式
4.方便程序的测试 可以用过注解去测试某项功能
5.整合各种插件和依赖 如spring-boot-start mybatis-spriing
Spring的诞生是为了解决什么问题的
为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题
2.基于XML的方式管理Bean
准备项目
1.创建一个工程Spring_demo
2.在pom.xml引入SpringIoc相关的依赖
4.0.0
com.qitai
spring_demo01
1.0-SNAPSHOT
1.8
1.8
org.springframework
spring-context
6.0.6
org.junit.jupiter
junit-jupiter-api
5.3.1
创建HappyComponent类
package com.qitai.ioc;
public class HappyComponent {
public void doWork(){
System.out.println("Spring Ioc Component");
}
}
引入Spring-bean.xml的配置文件
创建ioc容器
@Test
public void setApplicationContext() {
// 1.创建ioc 并读取配置文件
ApplicationContext context = new
ClassPathXmlApplicationContext("spring-bean-01.xml");
// 2.先创建容器 后配置文件
ClassPathXmlApplicationContext applicationContext = new
ClassPathXmlApplicationContext();
applicationContext.setConfigLocation("spring-bean-01.xml");
applicationContext.refresh();
}
获取bean
@Test
public void testExperiment() {
// 第一种创建方式
//1.创建ioc 读取配置文件
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("spring-bean-01.xml");
//2.获取bean对象
HappyComponent happyComponent = applicationContext.getBean("happyComponent", HappyComponent.class);
//3.调用其方法
happyComponent.doWork();
// 第二种创建方式
// 1.创建容器 加载配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
// 2.设置配置文件
context.setConfigLocation("spring-bean-01.xml");
// 3.后配置文件刷新
context.refresh();
// 4.获取bean
HappyComponent bean = context.getBean("happyComponent", HappyComponent.class);
bean.doWork();
}
bean的id是唯一的,bean需要包含了无参构造函数
2.1获取bean的三种方式
@Test
public void Methods(){
// 根据id获取
// 1.创建容器 加载配置文件
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring-bean-01.xml");
// 2.根据Bean获取Id 返回的是object类型 进行强制转换
HappyComponent happyComponent = (HappyComponent) context.getBean("happyComponent");
// 3.调用其方法
happyComponent.doWork();
// 根据类获取
// 1.创建容器 加载配置文件
ApplicationContext context1 =
new ClassPathXmlApplicationContext("spring-bean-01.xml");
// 2.根据bean获取类型
HappyComponent bean = context1.getBean(HappyComponent.class);
// 3.调用其方法
bean.doWork();
// 根据id和类型
// 1.创建容器 加载配置文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-bean-01.xml");
// 2.根据bean获取类型和id
HappyComponent happyComponents=applicationContext.getBean("happyComponent",HappyComponent.class);
// 3.调用其方法
happyComponents.doWork();
}
2.2 Bean属性赋值: setter注入
1.组件类添加属性
package com.qitai.ioc;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class HappyComponent {
private String componentName;
public void doWork(){
System.out.println("Spring Ioc Component");
}
}
2. 配置时给属性指定值
3.运行属性的获取bean数据
package com.qitai.ioc;
import lombok.Setter;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocBeanThree {
@Test
public void BeanThrees(){
// 1.创建容器 加载配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-bean-03.xml");
// 2.通过bean获取id和class
HappyComponent happyComponents =
context.getBean("happyComponent3", HappyComponent.class);
// 3. 获取属性值对象
String componentName = happyComponents.getComponentName();
// 4.输出结果
System.out.println(componentName);
}
}
2.4Bean属性赋值引入其他Bean
1.声明先的组件
package com.qitai.ioc;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class HappyMachine {
private String machineName;
}
2.原组件引入新组件
public class HappyComponent {
//添加属性
private String componentName;
public String getComponentName() {
return componentName;
}
//必须配置set方法,属性设置,ioc容器是通过set方法调用,进行属性赋值!!!
public void setComponentName(String componentName) {
this.componentName = componentName;
}
//引用新组件
private HappyMachine happyMachine;
public HappyMachine getHappyMachine() {
return happyMachine;
}
public void setHappyMachine(HappyMachine happyMachine) {
this.happyMachine = happyMachine;
}
public void doWork() {
System.out.println("HappyComponent.doWork");
}
}
3.在spring-bean.xml配置新的组件信息
4.组件之间引入配置
5.获取spring-bean04.xml
package com.qitai.ioc;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IocBeanFour {
@Test
public void IocBeanFours(){
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-bean-03.xml");
HappyComponent happyMachine
= context.getBean("happyComponent3", HappyComponent.class);
System.out.println(happyMachine.getHappyMachine().getMachineName());
}
}
2.5内部bean的声明
1.声明内部的bean
2.测试读取bean的内部类
package com.qitai.ioc;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class IodBeanFive {
@Test
public void IodBeanFives(){
// 1.创建容器 加载配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-bean05.xml");
// 2.获取id
HappyComponent happyComponents
= context.getBean("happyComponent5", HappyComponent.class);
// 3.先获取内部bean 在获取内部里面的bean
String machineName = happyComponents.getHappyMachine().getMachineName();
// 4.运行
System.out.println(machineName);
HappyMachine happyMachine = happyComponents.getHappyMachine();
System.out.println(happyMachine);
// 没有先获取内部bean 直接获取内部bean里面的bean是无法获取的
// 会出现运行时异常 NoSuchBeanDefinitionException
HappyMachine bean = context.getBean(HappyMachine.class);
System.out.println(bean);
}
}
2.6 引入外部Properties配置参数
1.引入依赖 mysql 和druid
mysql
mysql-connector-java
8.0.25
com.alibaba
druid
1.2.8
2.创建外部文件
jdbc.user=root
jdbc.password=root
jdbc.jdbc.url=jdbc:mysql:///news_headline
jdbc.driver=com.mysql.jdbc.Driver
3.引入属性文件
4.spring-bean配置连接池信息
5.运行测试获取连接
package com.qitai.ioc;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class JdbcBeanTest {
@Test
public void JdbcBeanTests(){
// 1.创建容器 加载配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-bean06.xml");
// 2.获取数据库的bean
DataSource bean = context.getBean(DataSource.class);
try {
// 3.获取连接
Connection connection = bean.getConnection();
// 4.运行
System.out.println(connection);
//5.关闭连接
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
1.FactoryBean使用场景 代理类的创建 第三方框架的整合
2.Factorybean应用
2.1准备实现factorybean
package com.qitai.facory;
import com.qitai.ioc.HappyMachine;
import org.springframework.beans.factory.FactoryBean;
public class HappyFactoryBean implements FactoryBean {
private String machineName;
public String getMachineName() {
return machineName;
}
public void setMachineName(String machineName) {
this.machineName = machineName;
}
@Override
public HappyMachine getObject() throws Exception {
// 创建对象
HappyMachine happyMachine = new HappyMachine();
// 设置引入的对象
happyMachine.setMachineName(this.machineName);
// 返回引入的对象
return happyMachine;
}
@Override
public Class> getObjectType() {
// 返回要生产的对象
return HappyMachine.class;
}
}
2.2配置FactoryBean实现类
2.3运行代码
package com.qitai.facory;
import com.qitai.ioc.HappyMachine;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class FactoryTest {
@Test
public void FactoryTests(){
// 创建容器 加载配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-beanfactory.xml");
// 获取bean加载
HappyMachine happyMachine7 = context.getBean("happyMachine7", HappyMachine.class);
// 拿到HappyMachine的bean对象
System.out.println(happyMachine7);
// 拿到factoryBean的bean对象
Object bean = context.getBean("&happyMachine7");
System.out.println("bean = " + bean);
}
}
2.3bean的作用域
1.作用域配置与测试
配置scope范围
2. 测试读取
package com.qitai.scop;
import com.qitai.ioc.HappyComponent;
import com.qitai.ioc.HappyMachine;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ScopTest {
@Test
public void ScopTests(){
// 创建容器 加载实例
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-scope-bean.xml");
// 获取bean对象
HappyMachine bean = context.getBean(HappyMachine.class);
HappyMachine beans = context.getBean(HappyMachine.class);
System.out.println(bean==beans);
// 获取bean对象
HappyComponent Hbean = context.getBean(HappyComponent.class);
HappyComponent Hbeans = context.getBean(HappyComponent.class);
System.out.println(Hbean==Hbeans);
}
}
Bean的生命周期
package com.qitai.post;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization");
System.out.println(bean+"..."+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization");
System.out.println(bean+"..."+beanName);
return bean;
}
}
init-method / destroy-method 配置
测试代码读取配置文件
@Test
public void testExperiment09() {
ApplicationContext iocContainer = new ClassPathXmlApplicationContext("spring-bean-09.xml");
}
注解方式管理bean
1.注解的理解,注解本身不能被执行,标记范围在类和方法上,执行被spring加载到实现业务上完成,自动装配来执行功能完成具体操作。
2.扫描的理解,开发人员在哪些地方标注了注解,需要扫描到完成具体的共能操作。
3.准备spring的依赖写到pom.xml中
4.0.0
com.qitai
spring_demo02
1.0-SNAPSHOT
17
17
UTF-8
org.springframework
spring-context
5.3.23
org.junit.jupiter
junit-jupiter-api
5.8.2
test
4.准备组件类
package com.qitai.common;
public class CommonComponent {
}
package com.qitai.controller;
public class CommonComponentController {
}
package com.qitai.service;
public class CommonComponentService {
}
package com.qitai.dao;
public class CommonComponentDao {
}
组件添加标记理解
spring有多个组件,可以标记在类上,将这些定义成springBean注解
组合注解 注解中包含注解
@Component 表示容器的一个注解,可以标记在Controller,Service,Dao上
1.@Repository 该注解标记在数据访问层,和Conponent的工鞥相同
2.@Service 该注解标记在业务层,和Conponent的工鞥相同
3.@Controller 该注解标记在控制层,和Conponent的工鞥相同
在源码中这个三个注解是从@Component注解基础上取出的新的名字
package com.qitai.common;
import org.springframework.stereotype.Component;
@Component
public class CommonComponent {
}
package com.qitai.controller;
import org.springframework.stereotype.Controller;
@Controller
public class CommonComponentController {
}
package com.qitai.service;
import org.springframework.stereotype.Service;
@Service
public class CommonComponentService {
}
package com.qitai.dao;
import org.springframework.stereotype.Repository;
@Repository
public class CommonComponentDao {
}
配置文件的扫描范围
1.基本扫描配置
2.指定排除组件
3.引入类型自动装配
package com.qitai.controller;
import com.qitai.service.CommonComponentService;
import lombok.Getter;
import org.springframework.stereotype.Controller;
@Controller(value = "tianDog")
public class CommonComponentController {
private CommonComponentService service;
public void getMessage(){
service.getMessage();
}
}
package com.qitai.service;
import com.qitai.dao.CommonComponentDao;
import org.springframework.stereotype.Service;
@Service("smallDog")
public class CommonComponentService {
private CommonComponentDao dao;
public void getMessage(){
dao.getMessage();
}
}
package com.qitai.dao;
import org.springframework.stereotype.Repository;
@Repository
public class CommonComponentDao {
public void getMessage() {
System.out.print("I am a soldier");
}
}
4.实现自动装配
@Autowired 注解标记成员变量
以上代码 成员变量加上@Autowired注解完成自动装配加载在ioc容器中
2.构造器完成自动装配
@Autowired
public CommonComponentController( CommonComponentService service){
this.service = service;
}
3.setter注入@Autowired注解
@Autowired
public void CommonComponentServices(CommonComponentService service){
this.service =service;
}
3.工作流程
Bean属性赋值 :基本属性赋值
@Value 通常进入外部化属性
声明外部配置文件
catalog.name=MovieCatalog
xml引入外部配置
spring-iocNoter.Onexml.xml
@Value注解读取配置
package com.qitai.common;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class CommonComponent {
@Value("${catalog:MovieCatalog}")
private String name;
}
基于配置类的方式管理bean
1.配置类和扫描注解的使用
xml+注解的方式
创建application.xml
测试容器的运行结果
@Test
public void IocNotesAppcation(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
System.out.println(context);
}
使用配置类注解完成功能
package com.qitai.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
@Configurable //标记是当前配置类 使用该注解 application.xml
//使用PropertySource注解可以外部配置文件 替代了
@PropertySource("classes:application.properties")
// 使用ComponentScan 注解可以进行包扫描 替代了
@ComponentScan(basePackages = {"com.qitai.common"})
public class MyConfiguration {
}
测试创建IoC容器
@Test
public void IocNotesApplicationOne(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
}
总结一下注解
@Configurable 被此注解标记的类 是配置类,启动时会自动装配到springIoc中 代替了 application.xml
@PropertySource 此注解标记外部配置文件 ,启动时会自动装配到springioc中 替代了
@ComponentScan 此注解是包扫描,启动是会自动扫描包的内容加载到springioc容器中替代了
Bean定义组件 xml
注解类方式实现
package com.qitai.config;
import com.alibaba.druid.pool.DruidAbstractDataSource;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configurable //标记是当前配置类 使用该注解 application.xml
//使用PropertySource注解可以外部配置文件 替代了
@PropertySource({"classes:application.properties","classes:jdbc.properties"})
// 使用ComponentScan 注解可以进行包扫描 替代了
@ComponentScan(basePackages = {"com.qitai.common"})
public class MyConfiguration {
// 配置方式可以使用bean注解+方法返回值
@Bean
public DataSource dataSource(@Value("${jdbc.username}") String username,
@Value("${jdbc.password}") String password,
@Value("${jdbc.url}") String url,
@Value("${jdbc.driver}") String driverClassName){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driverClassName);
return druidDataSource;
}
}
Bean注解的细节
初始化和销毁指定
package com.qitai.common;
public class Application {
public void init(){
System.out.println("进行了初始化");
}
}
package com.qitai.common;
public class ApplicationOne {
public void destruction(){
System.out.println("进行了销毁");
}
}
package com.qitai.common;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
public class AppConfig {
@Bean(initMethod = "init")
public Application a(){
return new Application();
}
@Bean(destroyMethod = "destruction")
public ApplicationOne b(){
return new ApplicationOne();
}
}
@Bean Scope作用域
@Scope("prototype")
@import允许从另一个加载bean
package com.qitai.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@Configurable
@Import(ConfigB.class)
public class ConfigA {
@Bean
public A a(){
return new A();
}
}
class A{
}
package com.qitai.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Repository;
@Configurable
public class ConfigB {
@Bean
public B b(){
return new B();
}
}
class B{
}
package com.qitai.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
private String name;
private Integer age;
}
package com.qitai.config;
import com.qitai.bean.User;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
@Configurable
public class BeanConfig {
@Bean(name = "bill")
public User user(){
return new User("bean bill",62);
}
@Bean(name = "linus")
public User userOne(){
return new User("bean linus",48);
}
}
@Test
public void test1(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanConfig.class);
Map beansOfType = applicationContext.getBeansOfType(User.class);
System.out.println(beansOfType);
}
package com.qitai.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Linux")){
return true;
}
return false;
}
}
package com.qitai.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowsCondition implements Condition {
// ConditionContext 判断条件能否使用上下文环境
// AnnotatedTypeMetadata 注解所在位置的信息
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取ioc使用bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 获取环境信息
Environment environment = context.getEnvironment();
// 获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
// 获取系统属性名
String property = environment.getProperty("os.name");
if (property.contains("Windows")){
return true;
}
return false;
}
}
package com.qitai.config;
import com.qitai.bean.User;
import com.qitai.condition.LinuxCondition;
import com.qitai.condition.WindowsCondition;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
@Configurable
public class BeanConfig {
@Conditional(WindowsCondition.class)
@Bean(name = "bill")
public User user(){
return new User("bean bill",62);
}
@Conditional(LinuxCondition.class)
@Bean(name = "linus")
public User userOne(){
return new User("bean linus",48);
}
}
xml和注解,xml加注解配置总结方式
1.xml的方式
1.1所有的内容都写到xml的配置文件中
2.1声明bean通过
3.1bean中包含基本标签id,class,属性
4.1引入外部的properties文件可以通过
5.1IoC具体容器实现选择ClassPathXmlApplicationContext对象
2.Xml加注解方式配置总结
2.1 注解负责标记ioc的类进行属性自动装配
2.2xml文件依然需要,需要通过 3.3标记ioc注解@Controller,@Service,@Component,@Repository 3.4标记DI注解:@Autowired @Qualifier @Resource @Value,@Bean 3.5IoC具体容器实现选择ClassPathXmlApplicationContext对象 整合spring6-tset5测试
package com.qitai;
import com.qitai.bean.User;
import com.qitai.config.BeanConfig;
import com.qitai.config.MyConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.util.Map;
@SpringJUnitConfig(BeanConfig.class)
public class IocNotes {
@Test
public void IocNotesOne(){
System.out.println("IocNotes...");
}
@Test
public void IocNotesAppcation(){
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
System.out.println(context);
}
@Test
public void IocNotesApplicationOne(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
}
@Test
public void test1(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanConfig.class);
String property = applicationContext.getEnvironment().getProperty("os.name");
System.out.println("当前系统是"+property);
Map