目录
一、Spring简介
Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。
目前是JavaEE开发的灵魂框架。他可以简化JavaEE开发,可以非常方便整合其他框架,无侵入的进行功能增强。
Spring的核心就是 控制反转(IoC)和面向切面(AOP) 。
二、IOC控制反转
控制反转,之前对象的控制权在类手上,现在反转后到了Spring手上。
2.1入门案例
- 导入依赖
导入SpringIOC相关依赖<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency>
- 编写配置文件
applicationContext.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:配置一个bean对象,将对象交给IOC容器管理 属性: id:bean的唯一标识,不能重复 class:设置bean对象所对应的类型 --> <bean id="helloworld" class="com.lx.pojo.helloWorld"></bean> </beans>
- 创建容器从容器中获取对象并测试
public class helloWorldTest { @Test public void testHelloWorld(){ //获取IOC容器 ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取IOC容器中的bean helloWorld helloworld = (helloWorld)ioc.getBean("helloworld"); helloworld.sayHello(); } }
2.3 Bean的常用属性配置
- id:bean的唯一标识,同一个Spring容器中不允许重复
- class:全类名,用于反射创建对象
- scope:scope主要有两个值:singleton和prototype
如果设置为singleton则一个容器中只会有这个一个bean对象。默认容器创建的时候就会创建该对象。
如果设置为prototype则一个容器中会有多个该bean对象。每次调用getBean方法获取时都会创建一个新对象。
三、DI依赖注入
依赖注入可以理解成IoC的一种应用场景,反转的是对象间依赖关系维护权。依赖注入就是IOC的具体实现
3.1 set方法注入
在要注入属性的bean标签中进行配置。前提是该类有提供属性对应的set方法。
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
private String[] hobby;
private Clazz clazz;
private Map<String,Teacher> map;
public Student(){
System.out.println("IOC通过无参构造创建对象");
}
public Student(Integer id, String name, Integer age, String sex) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
}
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;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
}
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
public Map<String, Teacher> getMap() {
return map;
}
public void setMap(Map<String, Teacher> map) {
this.map = map;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", hobby=" + Arrays.toString(hobby) +
", clazz=" + clazz +
", map=" + map +
'}';
}
}
<bean id="studentTwo" class="com.lx.pojo.Student">
<property name="id" value="001"></property>
<property name="name" value="张三"></property>
<property name="age" value="19"></property>
<property name="sex" value="男"></property>
</bean>
3.2 通过构造器注入
<!--
通过构造器赋值
顺序要和构造器的里参数的顺序一致
name:指定属性名
index:有参构造的参数索引
type:属性类型
-->
<bean id="studentThree" class="com.lx.pojo.Student">
<constructor-arg value="002"></constructor-arg>
<constructor-arg value="李四"></constructor-arg>
<constructor-arg value="30"></constructor-arg>
<constructor-arg value="女" name="sex" index="3" type="java.lang.String"></constructor-arg>
</bean>
3.3 复杂类型属性注入
配置如下:
<?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:util="http://www.springframework.org/schema/util"
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 http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="studentFour" class="com.lx.pojo.Student">
<property name="id" value="001"></property>
<!-- <property name="name" value="<张三>"></property>-->
<!--所有写在CDATA区中的字符都会被原样显示-->
<property name="name">
<value><![CDATA[<王五>]]></value>
</property>
<!--通过null标签给属性设置null-->
<property name="age"><null/></property>
<property name="sex" value="男"></property>
</bean>
<bean id="studentFive" class="com.lx.pojo.Student">
<property name="id" value="004"></property>
<property name="name" value="王五"></property>
<property name="age" value="19"></property>
<property name="sex" value="男"></property>
<!--ref:引用IOC容器中某个bean的id-->
<!--<property name="clazz" ref="clazzOne"></property>-->
<!--级联的方式,要保证提前为clazz属性赋值或实例化-->
<!--<property name="clazz.cid" value="005"></property>-->
<!--<property name="clazz.cname" value="软件2班"></property>-->
<!--内部bean-->
<property name="clazz">
<!--内部bean,只能在当前bean的内部使用,不能直接通过IOC容器获取-->
<bean id="clazzInner" class="com.lx.pojo.Clazz">
<property name="cid" value="006"></property>
<property name="cname" value="大数据"></property>
</bean>
</property>
<!--给数组类型赋值-->
<property name="hobby">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
<!--给map类型赋值:也可以使用util:map标签赋值-->
<property name="map">
<map>
<entry key="1" value-ref="teacherOne"></entry>
<entry key="2" value-ref="teacherOne"></entry>
</map>
</property>
</bean>
<!--p命名空间注入-->
<bean id="studentSix" class="com.lx.pojo.Student"
p:id="1009" p:age="18" p:name="张三"></bean>
<bean id="teacherOne" class="com.lx.pojo.Teacher">
<property name="tid" value="1"></property>
<property name="tname" value="张老师"></property>
</bean>
<bean id="clazzOne" class="com.lx.pojo.Clazz">
<property name="cid" value="1"></property>
<property name="cname" value="rj1class"></property>
</bean>
<bean id="clazzTwo" class="com.lx.pojo.Clazz">
<property name="cid" value="1"></property>
<property name="cname" value="rj1class"></property>
<property name="students" ref="studentList"></property>
<!-- <property name="students">-->
<!-- <list>-->
<!-- <ref bean="studentTwo"></ref>-->
<!-- <ref bean="studentThree"></ref>-->
<!-- <ref bean="studentFour"></ref>-->
<!-- </list>-->
<!-- </property>-->
</bean>
<!--配置一个集合类型的bean,需要使用util的约束-->
<util:list id="studentList">
<ref bean="studentTwo"></ref>
<ref bean="studentThree"></ref>
<ref bean="studentFour"></ref>
</util:list>
</beans>
四、Lombok
lombok作用 作用:简化用户创建实体对象(POJO)的过程,由插件自动的完成实体对象中常用方法的构建(get/set/toString/构造等)
1.导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
2.添加注解
@Data //根据属性生成set,get方法
@NoArgsConstructor //生成空参构造
@AllArgsConstructor //生成全参构造
public class Phone {
private double price;
private String name;
private String password;
private String path;
}
六、配置文件
6.1读取properties文件
我们可以让Spring读取properties文件中的key/value,然后使用其中的值。
在Spring配置文件中加入如下标签:指定要读取的文件的路径。
<context:property-placeholder location="classpath:filename.properties">
其中的classpath表示类加载路径下。
我们也会用到如下写法:classpath:*.properties 其中的 * 表示文件名任意。
注意:context命名空间的引入是否正确
6.2 使用配置文件中的值
<!--引入jdbc.properties配置文件-->
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
七、低频知识
7.1 bean的配置
7.1.1 name属性
- 我们可以用name属性来给bean取名。获取的时候就可以使用这个名字来获取了
7.1.2 lazy-init
- 可以控制bean的创建时间,如果设置为true就是在第一次获取该对象的时候才去创建。
7.1.3 init-method
- 可以用来设置初始化方法,设置完后容器创建完对象就会自动帮我们调用对应的方法。
@Data @NoArgsConstructor @AllArgsConstructor public class Student { private String name; private int id; private int age; //初始化方法 public void init(){ System.out.println("对学生对象进行初始化操作"); } }
注意:配置的初始化方法只能是空参的。<bean class="com.lx.domain.Student" id="student" init-method="init"></bean>
7.1.4 destroy-method
- 可以用来设置销毁之前调用的方法,设置完后容器销毁对象前就会自动帮我们调用对应的方法。
@Data @NoArgsConstructor @AllArgsConstructor public class Student { private String name; private int id; private int age; public void init(){ System.out.println("对学生对象进行初始化操作"); } public void close(){ System.out.println("对象销毁之前调用,用于释放资源"); } }
<bean class="com.lx.domain.Student" id="student" destroy-method="close"></bean>
7.1.5 factory-bean&factory-method
当我们需要让Spring容器使用工厂类来创建对象放入Spring容器的时候可以使用factory-bean和factory-method属性。
1.配置实例工厂创建对象
<!--创建实例工厂-->
<bean class="com.lx.factory.CarFactory" id="carFactory"></bean>
<!--使用实例工厂创建Car放入容器-->
<!--factory-bean 用来指定使用哪个工厂对象-->
<!--factory-method 用来指定使用哪个工厂方法-->
<bean factory-bean="carFactory" factory-method="getCar" id="car"></bean>
测试
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取car对象
Car c = (Car) app.getBean("car");
System.out.println(c);
2.配置静态工厂创建对象
<!--使用静态工厂创建Car放入容器-->
<bean class="com.lx.factory.CarStaticFactory" factory-method="getCar" id="car2"></bean>
3.也可以通过实现FactoryBean接口创建工厂
public class UserFactory implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
<bean id="userFactory" class="com.lx.factory.UserFactory"></bean>
测试类
/*
* FactoryBean是一个接口,需要定义一个类实现该接口
* getObject():通过一个对象交给IOC容器管理
* getObjectType():设置所提供对象的类型
* isSingleton():是否单例
*
* */
public class UserFactoryTest {
@Test
public void testUserFactory(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-factory.xml");
User user = context.getBean(User.class);
System.out.println(user);
}
}
八、生命周期
public class LifeCycleTest {
/*
* 生命周期:
* 1.实例化
* 2.依赖注入
* 3.后置处理器postProcessBeforeInitialization:在初始化之前执行 (实现BeanPostProcessor接口)
* 4.初始化 通过init-method指定初始方法
* 5.后置处理器postProcessAfterInitialization:在初始化之后执行 (实现BeanPostProcessor接口)
* 6.销毁 通过destroy-method指定销毁方法
* */
@Test
public void test(){
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
User user = context.getBean(User.class);
System.out.println(user);
context.close();
}
}
<!--
init-method:指定初始方法
destroy-method:指定销毁方法
-->
<bean id="user" class="com.lx.pojo.User" init-method="initMethod" destroy-method="destoryMethod">
<property name="id" value="12"></property>
<property name="username" value="admin"></property>
<property name="password" value="123456"></property>
</bean>
<!--将BeanPostProcessor的实现类定义成bean,后置处理器才能生效-->
<bean id="myBeanPostProcessor" class="com.lx.process.MyBeanPostProcessor"></bean>
后置处理器
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//在bean的生命周期初始化之前执行
System.out.println("MyBeanPostProcessor--->后置处理器postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//在bean的生命周期初始化之后执行
System.out.println("MyBeanPostProcessor--->后置处理器postProcessAfterInitialization");
return bean;
}
}