目录

1、spring简介

1.1 原生web开发存在的问题:

1.2 sprin框架

2、spring架构

3、spring IOC(控制反转)(xml配置文件配置)

基于xml配置文件:

3.1 spring框架的部署

3.2 spring框架的使用

3.4 DI注入

基于注解配置:

3.5 工厂bean的注入

4、spring IOC(控制反转)(纯java代码配置)

5、Bean的相关细节

5.1 Bean的作用域

5.2 Bean的生命周期

6、动态代理

6.1 JDK动态代理

6.2 CGLib动态代理

7、spring AOP(面向切面)

7.1 简介

7.2  AOP配置(基于xml配置文件,CGLib代理)

7.2  AOP配置(注解配置,xml配置包扫描)

7.3  AOP配置(纯java代码配置)定义配置类JavaConfig

7.4  AOP配置中的JDK代理和GBLib代理

8、补充笔记

8.1 条件注入

8.2 p名称空间注入

8.3 配置文件的注入

8.4 配置类

1、spring简介

1.1 原生web开发存在的问题:

(1)编程过程中代码的的耦合度过高(各层之间的相互调用,例如:service中需要实例化dao层)。

(2)使用原生的JDBC开发,代码繁琐,效率低。

(3)代码侵入性比较强(一个类中实例化另一个类),移植性低。失去面向接口编程开发的思想。

1.2 sprin框架

而spring框架就可以解决上述的问题,什么是spring框架:

(1)“轻量级控制反转(IOC)和面向切面(AOP)”的一个框架。

(2)spring中组合了多种设计模式(单例模式,适配器模式、工厂模式、代理模式等等)

①轻量级:代码侵入性低

②控制反转(IOC):将对象交给sprig容器来进行统一的管理,创建对象是也可以给属性赋值(DI注入)

③面向切面(AOP):即不改变原来业务代码的逻辑下,实现对业务的一个增强(使用到代理模式)

2、spring架构

(1)Data Access、Integrationg(数据访问/集成)

3、spring IOC(控制反转)(xml配置文件配置)

spring IOC控制反转即spring创建对象,管理对象,属性赋值。支持xml配置文件配置,也支持纯java代码的配。

xml配置文件的两种配置方式:

(1)基于xml配置文件配置

(2)基于注解配置

基于xml配置文件:

3.1 spring框架的部署

(1)创建Maven工程,添加spring依赖(core,beans,aop,expression,context),context中包含了这些依赖,所以导入context依赖够用。

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.12.RELEASE</version>
</dependency>

(2)创建spring配置文件。作用:通过配置文件,告诉spring容器需要创建管理那些对象。文件的名字可以自定义。这里命名为applicationContext.xml

3.2 spring框架的使用

定义一个实体类:User,三个属性(即目标Bean类)

使用spring工厂编码,在spring配置文件中创建User对象:

<!--    class:需要被配置的目标bean类,id:唯一标识--><bean class="com.benben.pojo.User" id="user"/>

这时候已经创建好了对象,进行测试,获取spring容器中的User对象:

@Testpublic void showInfo01(){//初始化spring容器,通过ClassPathXmlApplicationContext;类加载配置文件ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//通过spring容器,获取User对象User user = (User) context.getBean("user");System.out.println(user );}

3.4 DI注入

上述依赖spring容器创建好了一个user对象(IOC)。使用DI依赖注入可以对类的属性赋值,有三种方式:

创建bean:

User:

package com.benben.pojo;import lombok.*;import java.util.*;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.pojo* @Author: XiaoBenBen* @Date: 2022/7/2 15:17* @Description: TODO*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User {private int uid;private String uname;private String upwd;//日期对象private Date date;private Book book;private Book[] books;private List<Book> bookList;private Map<String,String> map;private Set<Book> set;private Properties properties;//初始化方法,对一些资源的初始化public void init(){}//销毁方法,对一些资源的回收操作public void destroy(){}}

Book:

package com.benben.pojo;import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.pojo* @Author: XiaoBenBen* @Date: 2022/7/3 14:32* @Description: TODO*/
@NoArgsConstructor
@AllArgsConstructor
public class Book {private int bid;private String bname;}

(1)set注入

set注入:在bean标签中通过配置property标签给对象属性赋值,本质上是通过反射调用set方法给属性赋值,所以目标bean中需要有set方法。

注意:name属性的名字与set方法名称对应,首字母小写。

a.简单类型以及字符串类型的注入

<!--    class:需要被配置的目标bean类,id:唯一标识--><bean class="com.benben.pojo.User" id="user"><property name="uid" value="1"/><property name="uname" value="张三"/><property name="upwd" value="李四"/></bean>

b. 日期对象注入

方式一:先在spring容器中注入一个Date对象,使用ref引入Date对象

方式二:在property中注入一个Date对象

<!--    日期对象--><bean class="java.util.Date" id="date"/>
<!--    方式一--><bean class="com.benben.pojo.User" id="user"><property name="date" ref="date"/></bean>
<!--    方式二--><bean class="com.benben.pojo.User" id="user1"><property name="date"><bean class="java.util.Date"/></property></bean>

c. 自定义类的注入

d.数组注入

e.集合的注入

f.Map的注入

g.Set的注入

h.Properties的注入

每种类别的注入都基本大同小异!

<bean class="com.benben.pojo.Book" id="book"/><bean class="com.benben.pojo.User" id="user3"><!--    自定义类注入--><property name="book" ref="book"/>
<!--        数组注入--><property name="books"><array><ref bean="book"/><bean class="com.benben.pojo.Book" id="book2"/></array></property>
<!--        集合注入list 标签表示数据类型是一个 List如果 list 中存放的数据是字符串,那么这里就直接使用 value如果 list 中存放的数据库是对象,那么可以使用 ref 去引用外部的 对象,也可以使用 bean 标签现场定义 Bean--><property name="bookList"><list><ref bean="book"/><bean class="com.benben.pojo.Book" id="book3"/></list></property>
<!--        map注入--><property name="map"><map><entry key="张三" value="18"/></map></property>
<!--        set注入--><property name="set"><set><ref bean="book"/></set></property>
<!--        properties注入--><property name="properties"><props><prop key="name">千锋</prop><prop key="address">广州</prop></props></property></bean>

(2)构造器注入

<!--    默认使用无参构造--><bean class="com.benben.pojo.Book" id="book"/>
<!--    使用构造方法注入--><bean class="com.benben.pojo.Book" id="book4"><constructor-arg index="0" value="1"/><constructor-arg value="三国演义"/></bean>

(3)接口注入(使用较少)

(4)自动注入(自动装配)

<!--自动装配:Spring在实例化当前bean的时候从Spring容器中找到匹配的实例赋值给当前bean的属性-->
<!--  autowire="byName" 根据当前Bean的属性名,在Spring容器中寻找匹配的对象,如果根据Name找到了bean,但是类型不匹配则会抛出异常。 -->
<!--  autowire="byType" 根据当前Bean的属性类型,在spring容器中寻找匹配的对象,如果根据类型找打了多个类型匹配的bean,也会抛出异常-->
<bean id="stu3" class="com.liguoqing.ioc.bean.Student" autowire="byName"></bean>

基于注解配置:

  • @Service、@Controller、@Repository这三个注解也可以将类声明给Spring管理,他们主要是语义上的区别

    • @Controller注解主要声明将控制器类配置给Spring管理,例如Servlet
    • @Service注解主要声明业务处理类配置给Spring管理,Service接口的实现类
    • @Repository注解主要声明持久化类配置给Spring管理,DAO接口
    • @Component除了控制器,Service,DAO之外的类一律使用此注解声明

在xml配置文件中添加:

<!--    声明使用注解配置--><context:annotation-config/>
<!--    声明Spring工厂注解的扫描范围--><context:component-scan base-package=""/>

基于注解配置即直接在目标bean类中添加注解,声明为spring容器管理。

package com.benben.pojo;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.pojo* @Author: XiaoBenBen* @Date: 2022/7/2 16:28* @Description: TODO*//*@Component(value="类的别名") value属性用于制定当前bean的id属性,或者叫别名。value属性也可以省略,如果省略,那么当前类的id默认为当前类名首字母改小写*/
@Component("myClass")   //将类声明给spring容器管理
@Scope("propotype")     //声明类为单例、非单例模式
@Lazy(true)             //声明为懒汉模式,默认为饿汉模式
public class MyClass {@Value("张三")      //注入普通属性private String name;/*1.属性注解、方法注解(set)声明当前属性自动装配,默认byType,默认必须(如果没有找到类型与属性类型匹配的bean则抛出异常)1.@Autowired(required = false)   通过required属性设置当前自动装配是否为必须(默认必须——如果没有找到类型与属性类型匹配的bean则抛出异常)*/@Autowiredprivate User user;/*属性注解,也用于声明属性自动装配默认装配方式为byName,如果根据byName没有找到相应的bean,则继续根据byType寻找对应的bean,根据byType如果没找到bean,或者找到不止一个类型匹配的bean则抛出异常。*/@Resourceprivate User user1;@PostConstruct      //声明为初始化方法public void init(){}@PreDestroy         //声明为销毁方法public void destory(){}}

3.5 工厂bean的注入

这个主要是解决一些第三方的 Bean,一些无法通过构造方法正常初始化、或者无法通过 set 方法正常为属性的赋值的 Bean,可以通过工厂 Bean 的方式将之注册到 Spring 容器中。

3.5.1 静态工厂的注入

静态工厂类:

package com.benben.factory;import com.benben.dao.UserDaoImpl;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.factory* @Author: XiaoBenBen* @Date: 2022/7/3 0:21* @Description: TODO*/
public class MyStaticFactory {public static UserDaoImpl getUserDaoImpl(){UserDaoImpl userDaoImpl = new UserDaoImpl( );return userDaoImpl;}
}

配置xml文件:factory-method属性里面为获取对象的方法。这个 Bean,将来会自动调用 getInstance 方法,并将该方法的返回值注入到 Spring 容器中。

<bean class="com.benben.factory.MyStaticFactory" id="myStaticFactory" factory-method="getUserDaoImpl"/>

测试:通过工厂bean可以拿到UserDaoImpl对象。

@Testpublic void showInfo05(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext02.xml");UserDaoImpl factory = (UserDaoImpl) context.getBean("myStaticFactory");factory.selectUser();}

3.5.2 实例工厂的注入

对于实例工厂方法,必须得先有一个工厂的实例,将来要通过这个实例才能调用工厂方法。

定义实例工厂:

package com.benben.factory;import com.benben.dao.UserDaoImpl;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.factory* @Author: XiaoBenBen* @Date: 2022/7/3 0:21* @Description: TODO*/
public class MyFactory {public UserDaoImpl getUserDaoImpl(){UserDaoImpl userDaoImpl = new UserDaoImpl( );return userDaoImpl;}
}

xml文件配置bean:factory-method属性里面为获取对象的方法。factory-bean属性中指定前面声明好的工厂bean。

<!--    先声明工厂bean--><bean class="com.benben.factory.MyFactory" id="myFactory"/>
<!--    factory-bean属性中指定前面声明好的工厂bean,--><bean factory-bean="myFactory" factory-method="getUserDaoImpl" id="mf"/>

测试:

@Testpublic void showInfo06(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext02.xml");UserDaoImpl mf = (UserDaoImpl) context.getBean("mf");mf.selectUser();}

3.5.3 spring官方方法

public class OkHttpClientFactoryBean implements FactoryBean<OkHttpClient> {/*** 返回真正的对象* @return* @throws Exception*/@Overridepublic OkHttpClient getObject() throws Exception {return new OkHttpClient.Builder()//设置服务端的读取超时时间.readTimeout(5000, TimeUnit.SECONDS)//连接超时.connectTimeout(5000, TimeUnit.SECONDS).build();}/*** 返回对象的类型* @return*/@Overridepublic Class<?> getObjectType() {return OkHttpClient.class;}/*** 这个对象是否是单例的* @return*/@Overridepublic boolean isSingleton() {return true;}
}

配置xml:

<bean class="com.qfedu.demo.OkHttpClientFactoryBean" id="client03"/>

4、spring IOC(控制反转)(纯java代码配置)

创建配置类JavaConfig,添加 @Configuration注解,表示为配置类

@ComponentScan(basePackages = "com.benben.pojo"):表示注解包扫描

/*** 这个是 Java 配置类,它的作用类似于 applicationContext.xml* @Configuration 表示这是一个配置类*/
@Configuration
public class JavaConfig {/*** @Bean 就表示将当前方法的返回值注册到 Spring 容器中* 默认情况下,方法名称就是 bean 的名字* 如果需要自定义 bean 的名称,那么在注解中配置即可* @return*/@Bean("u")User user() {User user = new User();user.setAddress("广州");user.setName("zhangsan");return user;}
}

测试类中加载配置类:

@Testpublic void showInfo02(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);User user = (User) context.getBean("user");System.out.println(user );}

5、Bean的相关细节

5.1 Bean的作用域

通过bean标签中的scope属性设置Bean的作用域。

(1)scope="singleton":单例模式(默认为饿汉模式,即spring容器初始化就创建对象,lazy-init="true":设置为懒汉模式。)

(2)scope="prototype":非单例模式(每次加载spring容器都会创建对象)

<bean class="java.util.Date" id="date" scope="prototype" lazy-init="true"/>

scope 有五种取值:

  • singleton:表示这个 bean 是单例的,从 Spring 容器中多次获取,拿到的是同一个 Bean。

  • prototype:每一次去 Spring 容器中,都可以获取到一个全新的 Bean。

  • request:在同一个请求中,如果多次获取同一个 Bean,获取到的是同一个(web 环境下生效)

  • session:在同一个 session 中,如果多次获取同一个 Bean,获取到的是同一个(web 环境下生效)

  • application:在同一个 web 应用中,如果多次获取同一个 Bean,获取到的是同一个(web 环境下生效)(web 环境下生效)

5.2 Bean的生命周期

在bean标签中可以通过 init-method 属性指定当前bean的初始化方法,初始化方法在构造器(spring容器默认使用无参构造创建对象)执行之后执行,通过 destroy-method 属性指定当前bean的销毁方法,销毁方法在对象销毁之前执行。属性里面写入方法名。

User类中添加方法:

//初始化方法,对一些资源的初始化public void init(){}//销毁方法,对一些资源的回收操作public void destroy(){}

配置:

<bean class="com.benben.pojo.User" id="user2" init-method="init" destroy-method="destroy"/>

6、动态代理

6.1 JDK动态代理

6.2 CGLib动态代理

7、spring AOP(面向切面)

7.1 简介

spring AOP 面向切面编程,即不改变原有的业务逻辑,对原有的业务逻辑进行拦截,在拦截的横切面上加强业务。(底层为动态代理)

①切点(pointcut):需要增强业务的地方,即此方法的位置

②通知/增强(advice):配置增加的业务的配置方式

③切面(aspect):切点+通知,简单的理解为需要增强业务的类

7.2  AOP配置(基于xml配置文件,CGLib代理)

添加spring-aspects依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context --><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.12.RELEASE</version></dependency>

定义一个增强业务类(切面类):TxManger

package com.benben.utils;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;import javax.sound.midi.Soundbank;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.utils* @Author: XiaoBenBen* @Date: 2022/7/2 17:31* @Description: TODO*/
public class TxManger {public void pc(){}public void begin(){System.out.println("开启事务" );}public void end(){System.out.println("关闭事务" );}public void myThrow(Exception e){System.out.println(e.getMessage());}public int run(){System.out.println("返回了" );return 1;}//环绕通知的方法,必须遵守如下的定义规则//1:必须带有一个ProceedingJoinPoint类型的参数,//2:必须有Object类型的返回值//3:在前后增强的业务逻辑之间执行Object v = point.proceed();//4: 方法最后返回 return v;public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("around之前" );Object proceed = point.proceed( );System.out.println("around之后");return proceed;}}

UserDaoImpl类中的selectUser()方法作为一个切点

package com.benben.dao;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.dao* @Author: XiaoBenBen* @Date: 2022/7/2 17:34* @Description: TODO*/
public class UserDaoImpl {public void selectUser(){
//        int a = 1/0;        //异常System.out.println("查询用户" );}
}

配置xml文件:

<bean class="com.benben.dao.UserDaoImpl" id="userDaoImpl"/><bean class="com.benben.utils.TxManger" id="txManger"/>
<!--    配置aop--><aop:config><!--id 表示切点的名称expression:表示切点的定义,第一个 * 表示方法返回值任意(这个位置也可以给定一个具体的返回类型)第二个 * 表示 service 下的所有类第三个 * 表示 任意方法.. 表示参数任意(参数可有可无,如果有,参数类型也是任意的)--><aop:pointcut id="userDao" expression="execution(* com.benben.dao.*.*(..))"/>
<!--        声明TxManger为切面类--><aop:aspect ref="txManger">
<!--            前置通知--><aop:before method="begin" pointcut-ref="userDao"/>
<!--            后置通知--><aop:after method="end" pointcut-ref="userDao"/>
<!--            异常通知切点方法抛出异常之后--><aop:after-throwing method="myThrow" pointcut-ref="userDao" throwing="e"/><!--   aop:after-returning 方法返回值返回之后,对于一个java方法而言return返回值也是方法的一部分因此”方法返回值返回之后“和”方法执行结束“是同一个时间点,所以after和after-returning根据配置的顺序决定执行的顺序--><aop:after-returning method="run" pointcut-ref="userDao"/>
<!--            环绕通知包括了所有,可以在之前,之后,异常,返回值--><aop:around method="around" pointcut-ref="userDao"/></aop:aspect></aop:config>

测试:

@Testpublic void showInfo03(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext01.xml");UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDaoImpl");userDao.selectUser();}

7.2  AOP配置(注解配置,xml配置包扫描)

<!--基于注解配置--><context:annotation-config/>
<!--    配置包扫描--><context:component-scan base-package="com.benben"/><!--基于注解配置的AOP代理--><aop:aspectj-autoproxy/>

7.3  AOP配置(纯java代码配置)
定义配置类JavaConfig

@Configuration     //表示这个一个配置类
@ComponentScan(basePackages = "com.benben")   //配置包扫描

package com.benben.utils;import org.springframework.context.annotation.*;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.utils* @Author: XiaoBenBen* @Date: 2022/7/2 16:48* @Description: TODO*/
@Configuration     //表示这个一个配置类
@ComponentScan(basePackages = "com.benben")   //配置包扫描
public class JavaConfig {}

切点所在类添加注解   @Repository    //声明给spring容器管理

package com.benben.dao;import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.dao* @Author: XiaoBenBen* @Date: 2022/7/2 17:34* @Description: TODO*/
@Repository    //声明给spring容器管理
public class UserDaoImpl {public void selectUser(){
//        int a = 1/0;        //异常System.out.println("查询用户" );}
}

定义切面类:添加注解

@Component  //声明给spring容器管理
@Aspect     //声明为切面类
@EnableAspectJAutoProxy    //开启自动代理

package com.benben.utils;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;/*** @BelongsProject: spring_demo01* @BelongsPackage: com.benben.utils* @Author: XiaoBenBen* @Date: 2022/7/2 17:31* @Description: TODO*/
@Component  //声明给spring容器管理
@Aspect     //声明为切面类
@EnableAspectJAutoProxy    //开启自动代理
public class TxManger {//声明切点@Pointcut("execution(* com.benben.dao.*.*(..))")public void pc(){}@Before("pc()")     //前置通知public void begin(){System.out.println("开启事务" );}@After("pc()")public void end(){System.out.println("关闭事务" );}@AfterThrowing(value = "pc()",throwing = "e")public void myThrow(Exception e){System.out.println(e.getMessage());}@AfterReturning(value = "pc()")public int run(){System.out.println("返回了" );return 1;}//环绕通知的方法,必须遵守如下的定义规则//1:必须带有一个ProceedingJoinPoint类型的参数,//2:必须有Object类型的返回值//3:在前后增强的业务逻辑之间执行Object v = point.proceed();//4: 方法最后返回 return v;@Around("pc()")public Object around(ProceedingJoinPoint point) throws Throwable {System.out.println("around之前" );Object proceed = point.proceed( );System.out.println("around之后");return proceed;}}

测试:

@Testpublic void showInfo04(){AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);UserDaoImpl userDaoImpl = (UserDaoImpl) context.getBean("userDaoImpl");userDaoImpl.selectUser();}

7.4  AOP配置中的JDK代理和GBLib代理

其中JDK代理,切点所在类需要实现Calculator接口,从spring容器中拿到的对象为spring容器自动生成的这个接口的实现类对象。

CGLib代理,本质从spring容器中拿到的为其子类的对象

@Testpublic void showInfo03(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext01.xml");/*JDK代理:userDao对象本质为spring容器自动生成的Calculator实现类的对象CGLib代理:userDao对象本质为spring容器生成的子类对象*/UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDaoImpl");userDao.selectUser();}

8、补充笔记

8.1 条件注入

条件注解是多环境配置的核心,思路就是提前准备好环境,所谓的环境,实际上就是 Condition 接口的实现类,然后在注册 Bean 的时候,通过 @Conditional 注解去指定环境,当满足某种条件的时候,bean 才会注入到 Spring 容器中。

两个非常经典的使用场景:

  • 项目中的多环境配置。

  • SpringBoot 中的自动化配置。

主要是使用 @Profile 注解,这个注解的本质就是 @Conditional 条件注解,用到的条件实际上就是 ProfileCondition。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
​/*** The set of profiles for which the annotated component should be registered.*/String[] value();
​
}

条件注解:

class ProfileCondition implements Condition {
​@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {//获取 Profile 注解的所有属性,其实这个注解只有一个 value 属性,属性的值是一个数组MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());if (attrs != null) {//将属性中的 value 读取出来,这个 value 的值实际上是一个 String 数组,遍历 String 数组for (Object value : attrs.get("value")) {//判断当前环境中,有没有 value 中的值if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {return true;}}return false;}return true;}
​
}

具体配置:

@Configuration
public class JavaConfig {/*** 开发环境的数据源** 通过 @Profile("dev") 注解可以指定当前的环境是开发环境* @return*/@Profile("dev")@Bean("ds")DataSource devDataSource() {DataSource ds = new DataSource();ds.setUsername("root");ds.setPassword("123");ds.setUrl("jdbc:mysql:///test01");return ds;}
​/*** 配置生产环境的数据源* @return*/@Profile("prod")@Bean("ds")DataSource prodDataSource() {DataSource ds = new DataSource();ds.setUsername("zhangsan");ds.setPassword("jdfkslajfl890324");ds.setUrl("jdbc:mysql://114.132.43.22/prod01");return ds;}
}

注册 Bean 的时候,通过 @Profile("prod") 注解来指定当前 Bean 在哪个环境下生效。

当启动 Spring 容器的时候,要为 Spring 容器指定当前的环境信息:

public class Demo01 {public static void main(String[] args) {//注意先不要写配置类,要先设置环境信息AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();//设置当前的环境信息ctx.getEnvironment().addActiveProfile("prod");ctx.register(JavaConfig.class);ctx.refresh();DataSource ds = ctx.getBean(DataSource.class);System.out.println("ds = " + ds);}
}

通过 XML 配置实现

首先在 xml 文件中,通过 beans 标签来指定环境:

<?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">
​<beans profile="dev"><!--将来写在这个标签中的 Bean,都是在 dev 环境下才会生效的 Bean--><bean class="com.qfedu.demo.p1.model.DataSource" id="dataSource"><property name="username" value="root"/><property name="password" value="123"/><property name="url" value="jdbc:mysql:///test01"/></bean></beans><beans profile="prod"><!--将来写在这个标签中的 Bean,都是在 prod 环境下才会生效的 Bean--><bean class="com.qfedu.demo.p1.model.DataSource" id="dataSource"><property name="username" value="root"/><property name="password" value="jkld3u$%^"/><property name="url" value="jdbc:mysql://11.22.11.22/test01"/></bean></beans>
</beans>

将来 Spring 容器启动的时候,会根据当前的环境信息去注册不同的 beans 标签中的 Bean。

启动容器的时候,设置一下当前环境即可:

public class Demo02 {public static void main(String[] args) {//先不要加载配置文件ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();ctx.getEnvironment().addActiveProfile("dev");//设置好当前环境之后,再去设置配置文件的位置ctx.setConfigLocation("applicationContext.xml");ctx.refresh();DataSource ds = ctx.getBean(DataSource.class);System.out.println("ds = " + ds);}
}

8.2 p名称空间注入

本质上为set方法注入:

<bean class="com.benben.pojo.User" id="user" p:uid="1" p:uname="张洼" p:upwd="1221"/>

测试:

@Testpublic void showInfo07(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext02.xml");User user = (User) context.getBean("user");System.out.println(user );}

8.3 配置文件的注入

主要是指 properties 配置文件的注入。

主要就是两个配置:

  • @PropertySource:项目启动的时候,将配置文件中的内容注册到 Spring 容器中。

  • @Value:从 Spring 容器要一个字符串回来。

java代码配置:

@Configuration
@PropertySource("classpath:db.properties")
public class DsConfig {//跟 Spring 容器要一个字符串回来@Value("${db.username}")String username;@Value("${db.password}")String password;@Value("${db.url}")String url;@BeanDataSource dataSource() {DataSource ds = new DataSource();ds.setPassword(password);ds.setUsername(username);ds.setUrl(url);return ds;}
}

xml配置:

 <!--这个配置的作用类似于 @PropertySource,就是将配置文件注册到 Spring 容器中--><context:property-placeholder location="classpath:db.properties"/><!--${db.url} 表示引用 Spring 容器中,key 为 db.url 的变量--><bean class="com.qfedu.demo.p1.model.DataSource" id="dataSource"><property name="url" value="${db.url}"/><property name="password" value="${db.password}"/><property name="username" value="${db.username}"/></bean>

8.4 配置类

  • @Configuration:这个注解表示当前类是一个配置类,那么当前类中,所有添加了 @Bean 注解的方法都会被注册到 Spring 容器中,如果有其他方法调用到一个添加了 @Bean 注解的方法,那么不会立马执行对应的方法,而是先去 Spring 容器中查看是否有对应的对象,如果有,则直接从容器中获取即可,如果容器中没有的话,才回去执行对应的方法。

  • @Component 虽然也可以加在配置类上,但是,如果有其他方法调用到一个添加了 @Bean 注解的方法,那么不会先去 Spring 容器中查看是否有对应的对象,而是直接执行对应的方法。所以一般在配置类中不使用 @Component 注解。如果一定要使用 @Component 注解,可以通过依赖注入来代替方法调用,类似下面这样:

/*** 向 Spring 容器注册一个 Author 对象** @return*/
@Bean
Author author() {Author author = new Author();author.setName("鲁迅");author.setAge(55);return author;
}
/*** 向 Spring 容器中注册一个 Book 对象** book 中有一个 author 对象,book 中的 author 和 spring 容器中的 author 是否是同一个对象?* @return*/
@Bean
Book book2(Author author) {Book book = new Book();book.setName("故事新编");book.setAuthor(author);book.setPrice(18.0);return book;
}

在这里,所有的方法都是 Spring 容器调用的,当 Spring 容器调用 book2 这个方法的时候,就会发现这个方法的执行需要一个 Author 类型的参数,那么此时 Spring 容器就会去查找是否有一个 Author,如果有,则直接作为参数传进来,如果 Spring 容器中没有这个对象,那么直接抛出异常。

Spring基础知识笔记相关推荐

  1. Spring家族-spring基础知识

    看了一段时间视频教程,还是需要总结一下,不然很容易忘的,笔记如下. 一.基本概念 1.三大框架SSM:Spring.SpringMvc.Mybaits,现在用的比较多是springboot 2.程序间 ...

  2. access2013数据库实验笔记_医学科研实验基础知识笔记(十):甲基化

    往期回顾 医学科研实验基础知识笔记(一):细胞增殖 医学科研实验基础知识笔记(二):细胞凋亡检测 医学科研实验基础知识笔记(三):细胞周期检测 医学科研实验基础知识笔记(四):细胞自噬研究策略 医学科 ...

  3. Java基础知识笔记-11_2-Swing用户界面组件

    Java基础知识笔记-11_2-Swing用户界面组件 这章教程两个版本,一个语法是非lambda表达式版本,另一个是lambda表达式版本 非lambda表达式版本 1 Java Swing概述 J ...

  4. 6-DoF问题相关基础知识笔记

    6-DoF问题相关基础知识笔记 一.什么是6-DoF,即6个自由度是什么? 二.PnP算法 三.BOP挑战与官方数据集简介 BOP数据集 BOP toolkit BOP挑战的介绍页面 四.相关论文 C ...

  5. 二代测序之SNV基础知识笔记总结

    二代测序之SNV基础知识笔记总结 文章目录 二代测序之SNV基础知识笔记总结 SNV基础知识 SNVs Mutation vs. Variant[变异和突变] 不同层次的突变 DNA: 1.编码DNA ...

  6. b站唐老师人工智能基础知识笔记

    b站唐老师人工智能基础知识笔记 0.机器学习(常用科学计算库的使用)基础定位.目标定位 1.机器学习概述 1.1.人工智能概述 1.2.人工智能发展历程 1.3.人工智能主要分支 1.4.机器学习工作 ...

  7. python详细基础知识笔记

    详细基础知识笔记 注: ·第一章 学习准备 1.1高级语言.机器语言.汇编语言 1.2 汇编.解释 1.3 静态语言.脚本语言 1.4 Python的历史 1.5 Python语言的优点.缺点 1.6 ...

  8. HTML基础知识笔记(0基础入门)

    HTML&CSS基础知识笔记 HTML 一.HTML介绍 二.实体 三.meta标签 四.语义化标签(一) 五.语义化标签(二) 六.语义化标签(三) 七.列表 八.超链接 九.图片标签 十. ...

  9. Unity3D基础知识笔记

    Unity3D基础知识笔记 一.Unity简介 1)Unity3D概念 2)Unity3D的特点 二.Unity3D的发展历史 三.软件安装 一.Unity简介 1)Unity3D概念 Unity是由 ...

最新文章

  1. zabbix 3.2 mysql模板_Zabbix-3.0.3使用自带模板监控MySQL
  2. Spring Boot (四)模板引擎Thymeleaf集成
  3. 深入了解softmax
  4. 回归分析残差不满足正态分布_线性回归思路梳理!精华必看!
  5. sklearn自学指南(part57)--协方差估计
  6. 廉价raid_如何查找80行代码中的廉价航班
  7. C++ 多态原理初步01
  8. tinkerpop mysql_图论数据库未来的发展方向?
  9. Java 并发编程阅读笔记
  10. python入门经典-Python入门经典书籍有哪些?有这三本就够了
  11. 总结_____大二上
  12. “the import java.io cannot be resolved”错误的解决方法
  13. TP框架漏洞复现(持续更新)
  14. python就业班2017_2017黑马Python就业班视频教程
  15. 节后上班 北京车辆尾号限行2日轮换
  16. Android静默安装实现方案,仿360手机助手秒装和智能安装功能
  17. Markdown空两格,图片居中
  18. 手机照片局部放大镜_如何为不识字的老年人挑选一款合适的智能手机
  19. 【网页设计】HTML做一个属于我的音乐页面(纯html代码)
  20. D3.js从入门指南

热门文章

  1. C语言实现memmove
  2. PKCS#11标准解读-Cryptoki库如何工作(4)
  3. [二进制安全]CTF中那些古典密码
  4. Android逆向 微信小游戏破解(一):我要当皇上满级修改
  5. 网络安全-防守-护网
  6. 工作区域(或内部表)“LT_RKWA“不是扁平的,或者包含参考或内部表作为组件
  7. 智云通CRM:如何做出正确的客户选择?
  8. Win10磁盘上出现黄色感叹号和小锁的解决办法
  9. 说说这些天我们遇到的面试官
  10. nodejs.ReferenceError: ctx is not defined解决方法