Spring概述及体系介绍
Spring概述
①Spring是一个开源框架
②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,有效的降低代码的耦合度,极大的方便项目的后期维护、升级和扩展。
③Spring是一个IOC(DI)和AOP容器框架。
④Spring的优良特性
[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
[2]控制反转:IOC——Inversion of Control,指的是将对象的创建权交给Spring去创建。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。
[3]依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设置,而是通过配置赋值。
[4]面向切面编程:Aspect Oriented Programming——AOP
[5]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
[6]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
[7]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)
(1)核心容器:包括Core、Beans、Context、EL模块
Core模块:封装了框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类。
Beans模块:提供了框架的基础部分,包括反转控制和依赖注入。其中Bean Factory是容器核心,本质是“工厂设计模式”的实现,而且无需编程实现“单例设计模式”,单例完全由容器控制,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正把你从程序逻辑中把维护对象之间的依赖关系提取出来,所有这些依赖关系都由BeanFactory来维护。
Context模块:以Core和Beans为基础,集成Beans模块功能并添加资源绑定、数据验证、国际化、Java EE支持、容器生命周期、事件传播等;核心接口是ApplicationContext。
EL模块:提供强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring 容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。
Spring安装配置
创建工程
添加maven依赖
<dependencies>
<!-- Spring IOC最小依赖是beans、context,我们引入context依赖,maven会自动将beans依赖一并引入 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
快速开始
1.编写配置文件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.lanou3g.spring" />
</beans>
IOC
ApplicationContext实现类
在Spring中,构成应用程序主干并由Spring IOC容器管理的对象称为bean。 bean是一个由Spring IOC容器实例化,组装和管理的对象。ApplicationContext代表了Spring IOC容器,通过它我们可以实现对Spring IOC容器的所有操作:实例化、配置、组装bean。 通常我们在开发中直接用到的是ApplicatoinContext接口和它的各种实现类。
ClassPathXmlApplicationContext
用于加载类路径下的spring配置文件,通常用于控制台程序
使用方法:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentService ss = ctx.getBean(StudentService.class);
System.out.println(ss);
AnnotationConfigApplicationContext
用于初始化通过注解方式配置的ioc容器
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyServiceImpl();
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
System.out.println(myService);
}
}
Application初始化路径
路径前缀
// 前缀classpath:表示的是项目的classpath下相对路径
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
路径中的通配符
// 使用通配符加载所有符合要求的文件
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");
通过xml方式配置管理bean
优点:对代码没有任何侵入性, 改了配置不需要重新编译、打包
缺点:配置相比注解的方式要繁琐很多,工程量比较大
public interface MessageDao {
List<String> queryAllMessageTitle();
}
public class MessageServiceImpl {
MessageDao messageDao;
public String choiceOneMessageTitle() {
List<String> messageList = messageDao.queryAllMessageTitle();
int idx = new Random().nextInt(messageList.size());
return messageList.get(idx);
}
public MessageDao getMessageDao() {
return messageDao;
}
public void setMessageDao(MessageDao messageDao) {
this.messageDao = messageDao;
}
}
<bean id="messageService" class="com.lanou3g.spring.service.MessageServiceImpl">
<property name="messageDao" ref="md" />
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testIOCQuicklyStart(ctx);
}
private void testIOCQuicklyStart(ApplicationContext ctx) {
// message相关的bean是通过xml方式配置
MessageServiceImpl messageService = ctx.getBean("messageService", MessageServiceImpl.class);
String title = messageService.choiceOneMessageTitle();
System.out.println(title);
}
通过注解方式管理bean
优点:配置简单。由于Java类中已经包含很上下文信息,所有在Java类上直接加注解可以省略很多属性。
缺点:对代码有侵入性,如果改了是基于注解的配置信息改变了,需要重新编译、打包
public interface Fruit {
void eatFruit();
}
// 用@Configuration注解的类就相当于是一个xml的配置文件
@Configuration
@Import(MyConf.class) // <import resource="" />
@ImportResource("applicationContext.xml")
//@ComponentScan(basePackages = "com.lanou3g.spring")
public class App {
@Autowired
@Qualifier("ap") //这里写的apple对应的是bean的id或者name
private Fruit fruit;
public void testFruit() {
fruit.eatFruit();
}
public Fruit getFruit() {
return fruit;
}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
}
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testIOCQuicklyStart(ctx);
}
private void testIOCQuicklyStart(ApplicationContext ctx) {
//app相关的bean是通过注解方式配置
App app = ctx.getBean("app", App.class);
app.testFruit();
}
xml和注解方式混合使用
Spring提供@Configuration
、@Bean
等注解的方式并不是为了要完全取代xml配置方式, 而是要看使用场合,比如数据源的配置, 就不适合通过注解来配置。否则数据源配置一发生变化就得改代码。
下面是一种典型的混合配置示范:
在xml中配置数据源
<beans>
<!-- 开启注解配置支持 -->
<!-- <context:annotation-config/> -->
<!-- 扫描注解的包路径,配置了这个后无需再配置上面那个 -->
<context:component-scan base-package="com.lanou3g.spring"/>
<!-- 读取properties配置文件,用于替换spring配置中的${}占位符 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean class="com.acme.App"/>
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
jdbc.url=jdbc:mysql://localhost:3306/XXXX(数据库名)?charsetEncoding=utf8
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
通过java注解配置bean和依赖注入
@Configuration
public class App {
@Autowired
private DataSource dataSource;
@Bean
public Student student() {
return new Student(dataSource);
}
@Bean
public People people() {
return new People(student());
}
}
启动入口
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
People people = ctx.getBean(People.class);
// ...
}
用注解的类导入xml配置
public interface Fruit {
void eatFruit();
}
// 如果我们不写value属性,默认bean的名称就是类名首字母小写
// 这里就是banana
@Component
public class Banana implements Fruit {
@Override
public void eatFruit() {
System.out.println("eating Banana");
}
}
@Configuration // <beans>
public class MyConf {
@Bean("sb") // <bean id="sb">
public Fruit smallBanana() {
return new Banana();
}
}
public class Student {
private String sname;
private String nickName;
private Fruit fruit;
public Student() {}
public Student(String sname, String nickName, Fruit fruit) {
this.sname = sname;
this.nickName = nickName;
this.fruit = fruit;
}
public String getSname() {
return this.sname;
}
public String getNickName() {
return this.nickName;
}
public Fruit getFruit() {return this.fruit;}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
}
<!-- name属性也是用于给bean起名,getBean的时候使用,与id属性不同的是,name属性的值可以有多个 -->
<bean id="student" name="stu,student1,sd1" class="com.lanou3g.spring.bean.Student">
<constructor-arg name="nickName" value="三哥" />
<constructor-arg name="sname" value="张三" />
<constructor-arg name="fruit" ref="banana" />
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher(). testAnnotationImportXml(ctx);
}
/**
* 练习用@Configuration注解的类导入xml配置
* @param ctx
*/
public void testAnnotationImportXml(ApplicationContext ctx) {
Fruit fruit = ctx.getBean("sb", Fruit.class);
System.out.println(fruit);
// 获取applicationContext.xml中配置的name属性为:stu,student1,sd1
Student stu = ctx.getBean("sd1", Student.class);
System.out.println(stu.getNickName());
}
深入了解IOC
管理bean的作用域
Scope | Description |
---|---|
singleton | 单例。在整个ioc容器中只有一个此类型的示例。(默认值) |
prototype | 原型。每次使用都要创建一个新的对象。 |
request | 对象的实例仅在一个request请求周期内有效,仅限在web环境中使用。 |
session | 对象的实例仅在一个session会话周期内有效,仅限在web环境中使用。 |
application | 对象的实例在整个application生命周期内有效,仅限在web环境中使用。 |
websocket | 对象的实例仅在一个websocket生命周期内有效,仅限在web环境中使用。 |
常用的作用域只有两个:singleton,prototype。不写的话默认是singleton。
<bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" scope="singleton"/>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testScope(ctx);
}
public void testScope(ApplicationContext ctx){
MessageDao messageDao1=ctx.getBean("md",MessageDao.class);
System.out.println(messageDao1);
MessageDao messageDao2=ctx.getBean("md",MessageDao.class);
System.out.println(messageDao2);
MessageDao messageDao3=ctx.getBean("md",MessageDao.class);
System.out.println(messageDao3);
}
管理bean的生命周期
<bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" scope="singleton"
init-method="myInit" destroy-method="myDestroy"/>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testLifeCycle(ctx);
}
/**
* 练习IOC容器中bean的生命周期
*/
public void testLifeCycle(ApplicationContext ctx) {
MessageDao messageDao = ctx.getBean("md", MessageDao.class);
System.out.println(messageDao);
}
使用id属性和name属性命名bean
使用id属性命名bean
id属性的值只能指定一个,不建议含有特殊字符(虽然自spring3.1开始id属性的值可以包含任意字符)。
使用name属性命名bean
使用name属性可以给一个bean指定多个名称,多个值之间可以用","、";"或空格分开
注: 无论是id属性还是bean属性都需要保证整个IOC容器内唯一,并且id属性的值和name属性的值也不能重复
我们可以同时指定id和name属性。 也可以都不指定,如果都不指定,IOC容器会为该bean生成一个唯一的名称。
实例化bean的方式
通过构造方法实例化
这种方式是最常用的方式,适合绝大多数的javabean,因为我们的java类无需继承任何父类或实现任何接口。但是我们通常需要提供一个无参的构造方法。
通过静态工厂方法实例化
这种方式适合需要让Spring管理自己实现的单例类,用的很少。因为通过Spring IOC容器我们只需配置一下scope="singleton"就可以实现单例了。
通过非静态工厂方法实例化
这种方式用的也不多,只有特定场合才会用到。
三种实例化bean的方式代码如下:
<!-- 通过构造方法创建bean -->
<!-- name属性也是用于给bean起名,getBean的时候使用,与id属性不同的是,name属性的值可以有多个 -->
<bean id="student" name="stu,student1,sd1" class="com.lanou3g.spring.bean.Student">
<constructor-arg name="nickName" value="三哥" />
<constructor-arg name="sname" value="张三" />
<constructor-arg name="fruit" ref="banana" />
</bean>
<!-- 通过静态工厂方法创建bean -->
<bean id="big_apple" class="com.lanou3g.spring.bean.FruitFactory" factory-method="produceFruit">
<constructor-arg name="name" value="banana" />
</bean>
<!-- 通过非静态工厂方法创建bean -->
<bean id="fruitFactory" class="com.lanou3g.spring.bean.FruitFactory" />
<bean id="big_banana" factory-bean="fruitFactory" factory-method="produceFruitByInstrance">
<constructor-arg name="name" value="banana" />
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testBeanInit(ctx);
}
/**
* 练习bean的各种初始化配置
*/
public void testBeanInit(ApplicationContext ctx) {
// 通过带参数构造方法初始化bean
/*Student lazyStudent = ctx.getBean(Student.class);
System.out.println("名称:" + lazyStudent.getSname());
System.out.println("爱称:" + lazyStudent.getNickName());
lazyStudent.getFruit().eatFruit();*/
//通过静态工厂方法来初始化bean
/*Object obj = ctx.getBean("big_apple");
System.out.println(obj);*/
// 通过非静态工厂方法来初始化bean
Object obj = ctx.getBean("big_banana");
System.out.println(obj);
System.out.println(obj.getClass());
}
优雅的关闭SpringIOC容器
我们可以通过registerShutdownHook()实现在JVM停止的同时优雅的关闭IOC容器
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 给上面初始化的IOC容器添加一个基于JVM的关闭回调,
ctx.registerShutdownHook();
// 其他业务代码...
// 在main方法运行结束后,IOC容器会在JVM的关闭回调中正常关闭
}
2.依赖注入(DI)
/**
* Service
*/
public interface StudentService {
List<Student> queryStudents();
}
public class StudentServiceImpl implements StudentService {
// 通过Spring DI自动注入
@Autowired
private StudentDao studentDao;
@Override
public List<Student> queryStudents() {
return studentDao.queryStudents();
}
}
/**
* dao
*/
public interface StudentDao {
List<Student> queryStudents();
}
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> queryStudents() {
return new ArrayList<>();
}
}
/**
* 实体类
*/
@Setter
@Getter
@Component
public class Student {
private Integer id;
private String sname;
private Integer age;
private String gender;
private String nickName;
}
3.加载配置文件,获取SpringContext管理的Bean(控制反转IOC)
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = ctx.getBean(Student.class);
System.out.println(stu);
}
懒加载
SpringIOC容器默认会在启动的时候初始化我们配置的所有bean,但有时我们想让一些bean延迟初始化的时机,在我们getBean的时候再初始化。
这时就需要使用懒加载,在bean上面添加lazy-init属性,属性值可以是true、false、default。 默认情况是false。
懒加载的优缺点:
对象使用的时候才去创建,节省资源,但是不利于提前发现错误。
<bean id="md" class="com.lanou3g.spring.dao.MessageDaoImpl" lazy-init="true"
init-method="myInit" destroy-method="myDestroy"/>
DI
构造方法注入
package x.y;
public class ThingOne {
private int age;
private String sname;
private int gender;
private ThingTwo thingTwo;
public ThingOne(int age, ThingTwo thingTwo, String sname, int gender) {
this.age = age;
this.thingTwo = thingTwo;
this.sname = sname;
this.gender = gender;
// ...
}
}
public class ThingTwo {
// ...
}
有参注入
无参注入
<beans>
<!-- 有参注入 -->
<bean id="beanOne" class="x.y.ThingOne">
<!-- 通过此标签注入构造方法中的参数 -->
<constructor-arg name="age" value="18" />
<constructor-arg type="java.lang.String" value="张三" />
<constructor-arg ref="beanTwo"/>
</bean>
<!-- 无参注入 -->
<bean id="beanTwo" class="x.y.ThingTwo"/>
</beans>
通过c命名空间注入参数
先在beans中添加c的schema,再使用c代替标签
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 通过c命名空间来注入构造参数 -->
<!--<bean id="yunjie2" class="com.lanou3g.spring.bean.YunJie">
<constructor-arg name="sname" value="雲杰" />
</bean>-->
<!-- 等效于上面的配置 -->
<bean id="yunjie2" class="com.lanou3g.spring.bean.YunJie" c:sname="雲杰" />
</beans>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testInjectC(ctx);
}
/**
* 测试通过c命名空间注入属性和构造参数
*/
public void testInjectC(ApplicationContext ctx) {
YunJie yunJie2 = ctx.getBean("yunjie2", YunJie.class);
System.out.println("通过c注入构造参数, sname: " +yunJie2.getSname());
}
setter注入
注入匿名内部bean
<!-- 给Student注入一个匿名内部bean -->
<bean id="stu1" class="com.lanou3g.spring.bean.Student">
<property name="fruit">
<bean class="com.lanou3g.spring.simple.Apple" />
</property>
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testInjectInnerBean(ctx);
}
/**
* 通过<property>标签注入一个匿名内部类
*/
public void testInjectInnerBean(ApplicationContext ctx){
Student stu=ctx.getBean("stu1",Student.class);
stu.getFruit().eatFruit();
}
注入集合类属性
注入null,空字符串类型属性值
注入复合属性值
<bean id="saiSai" class="com.lanou3g.spring.bean.JinSaiSai">
<property name="hobbies">
<list>
<value>游泳</value>
<value type="java.lang.Integer">0034</value>
<value>写代码</value>
<value>玩游戏</value>
</list>
</property>
<property name="gameTitles">
<map>
<entry key="LOL" value="嘴强王者"></entry>
<entry key="王者农药" value="甩锅大神"></entry>
<entry key="和平精英">
<null />
</entry>
</map>
</property>
<property name="nickName">
<null />
</property>
<property name="yinSaiSai">
<bean class="com.lanou3g.spring.bean.YinSaiSai" />
</property>
<property name="yinSaiSai.age" value="28" />
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testInjectListMap(ctx);
}
/**
* 注入集合类属性
*注入null,空字符串类型属性值
*注入复合属性值
*/
public void testInjectListMap(ApplicationContext ctx){
JinSaiSai saisai=ctx.getBean(JinSaiSai.class);
//获取注入的list属性
List<Object> hobbies=saisai.getHobbies();
for (Object hobby:hobbies) {
System.out.println("类型:"+hobby.getClass()+",值:"+hobby);
}
//获取注入的map属性
System.out.println(saisai.getGameTitles());
//获取普通属性nickName
System.out.println("nickName:"+saisai.getNickName());
//获取关联对象中的属性值
System.out.println("银赛赛中的age:"+saisai.getYinSaiSai().getAge());
}
注入外部properties文件中的属性值
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="jdbcConf" class="com.lanou3g.spring.bean.JDBCConf">
<property name="url" value="${jdbc.url}"/>
<property name="driver" value="${jdbc.driver}"/>
<property name="userName" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testInjectProperties(ctx);
}
/**
* 练习注入外部properties配置文件
*
*/
public void testInjectProperties(ApplicationContext ctx){
JDBCConf jdbcConf=ctx.getBean(JDBCConf.class);
System.out.println(jdbcConf.getUrl());
System.out.println(jdbcConf.getDriver());
System.out.println(jdbcConf.getUserName());
System.out.println(jdbcConf.getPassword());
}
通过p命名空间注入属性
先在beans中添加p的schema,再使用p代替标签
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 通过p命名空间来注入属性 -->
<!--<bean id="yunjie1" class="com.lanou3g.spring.bean.YunJie">
<property name="sname" value="云姐" />
</bean>-->
<!-- 等效于上面的配置 -->
<bean id="yunjie1" class="com.lanou3g.spring.bean.YunJie" p:sname="云姐" />
</beans>
public static void main(String[] args) {
// ClassPathXmlApplicationContext用于初始化ioc容器(基于类路径下基于xml方式的配置)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
new Launcher().testInjectP(ctx);
}
/**
* 测试通过p命名空间注入属性和构造参数
*/
public void testInjectP(ApplicationContext ctx) {
YunJie yunJie1 = ctx.getBean("yunjie1", YunJie.class);
System.out.println("yunjie1(通过p注入属性setter), sname: " + yunJie1.getSname());
}