2021-07-24 Spring
目录
Spring优点
- spring是一个开源的买南非框架
- spring是一个轻量级的、非入侵式的框架
- IOC、AOP
- 支持事务处理,对框架整合的支持
spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
IOC
控制反转,就是获得依赖对象的方式反转了,通过 xml 或注解获取指定对象。
经常说的DI(依赖注入)就是IOC的一种实现方式。
IOC创建对象的方式
-
默认使用无参构造创建对象。
-
使用有参构造函数
<!-- 下标赋值 --> <bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean><!-- 类型赋值 但同类型两个参数会歧义--> <bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean><!-- 参数名赋值 --> <bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateAnswer" value="42"/> </bean><!-- 引用 --> <bean id="beanOne" class="x.y.ThingOne"> <constructor-arg ref="beanTwo"/> <constructor-arg ref="beanThree"/> </bean> <bean id="beanTwo" class="x.y.ThingTwo"/> <bean id="beanThree" class="x.y.ThingThree"/>
依赖注入(DI)
1. 构造器注入
就是上文中四种构造器。
2. Set方式注入
- 依赖:bean对象的创建依赖于容器。
- 注入:bean对象中的所有属性由容器来注入。
对象
Student.java
package com.klaus.pojo;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String, String >card;
private Set<String> games;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
}
注入
beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.klaus.pojo.Student">
<!-- 普通值注入 -->
<property name="name" value="刘佳伟"/>
<!-- Bean注入, ref-->
<property name="address" ref="address"/>
<!-- 数组注入 -->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
</array>
</property>
<!-- list -->
<property name="hobbies">
<list>
<value>游泳</value>
<value>睡觉</value>
</list>
</property>
<!-- map -->
<property name="card">
<map>
<entry key="学号" value="2018012966"/>
</map>
</property>
<!-- set -->
<property name="games">
<value>三国杀</value>
<value>LOL</value>
</property>
<!-- null 注入 -->
<property name="wife">
<null/>
</property>
<!-- properties -->
<property name="info">
<props>
<prop key="status">student</prop>
</props>
</property>
</bean>
<bean id="address" class="com.klaus.pojo.Address"/>
</beans>
3. 拓展方式注入
3.1 p命名空间
p标签可以直接注入。
不过需要加上xmlns:p="http://www.springframework.org/schema/p"。
user.java
package com.klaus.pojo;
public class User {
String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
beans.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- p ~ property -->
<bean id="user" class="com.klaus.pojo.User" p:name="刘佳伟"/>
</beans>
3.2 c命名空间
必须有有参构造函数。
使用时需要加上xmlns:c="http://www.springframework.org/schema/c"xml 约束。
user.java
package com.klaus.pojo;
public class User {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
beans.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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.klaus.pojo.User" c:age="18" c:name="刘佳伟"/>
</beans>
Bean的作用域
-
单例模式
默认作用域,全局创建的只有这一个对象。例如:
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="user" class="com.klaus.pojo.User" c:age="18" c:name="刘佳伟" /> </beans>@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("user.xml"); User user1 = context.getBean("user", User.class); User user2 = context.getBean("user", User.class); System.out.println(user1 == user2); }输出结果为
true。
-
原型模式
每次从容器中get的都是新的对象。
然后同样的测试示例,bean的作用范围改成prototype结果就是false。
<bean id="user" class="com.klaus.pojo.User" c:age="18" c:name="刘佳伟" scope="prototype"/> -
其余的request、session、application在web应用中。
Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring在上下文中自动寻找,并自动给bean装配属性
在Spring中由三种装配方式:
- 在xml中显式配置
- 在java中显式配置
- 隐式的自动装配
测试环境
// Cat.java
package com.klaus.pojo;
public class Cat {
public void shout(){
System.out.println("喵喵喵");
}
}
// Dog.java
package com.klaus.pojo;
public class Dog {
public void shout(){
System.out.println("汪汪汪");
}
}
// People.java
package com.klaus.pojo;
public class People {
private Dog dog;
private Cat cat;
private String name;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"dog=" + dog +
", cat=" + cat +
", name='" + name + '\'' +
'}';
}
}
<!-- beans.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.klaus.pojo.Cat" />
<bean id="dog" class="com.klaus.pojo.Dog" />
<bean id="people" class="com.klaus.pojo.People">
<property name="name" value="刘佳伟"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
</beans>
byName自动装配
**工作机制:**自动在容器上下文中查找,和自己对象 set 方法后面的值对应的 Bean id。
如下,依然可以正确运行。
<bean id="people" class="com.klaus.pojo.People" autowire="byName">
<property name="name" value="刘佳伟"/>
</bean>
byType自动装配
**工作机制:**自动在容器上下文查找 和自己对象属性类型相同的 Bean。所以要保证类型唯一,否则会出错。
<!-- byType可以不需要id -->
<bean class="com.klaus.pojo.People" autowire="byType">
注:
- 使用byName时,需要保证所有 bean 的 id 唯一,并且这个 bean 要与自动注入的属性的 set 方法的值一致。
- 使用byType时,需要保证所有 bean 的 class 唯一,并且这个 bean 要和自动注入属性的类型一致。
使用注解实现自动装配
配置注解的支持<context:annotation-config/>
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
直接在属性上使用即可;
使用 Autowired 可以不用编写 set 方法,前提是自动装配的属性在容器中存在,且名字符合 byName (还是通过byName实现的)。
当环境如下时
public class People {
@Autowired
private Dog dog;
@Autowired
private Cat cat;
private String name;
...
}
<bean id="dog11" class="com.klaus.pojo.Dog"/>
<bean id="dog111" class="com.klaus.pojo.Dog"/>
这时候可以使用@Qualifier(value = "dog11")来指定。
即
public class People {
@Autowired
@Qualifier(value = "dog11")
private Dog dog;
@Autowired
private Cat cat;
private String name;
...
}
@Nullable 字段标记了这个注解,说明这个字段为null
@Autowired的require属性为false,说明这个对象可以为null,否则不允许为空
@Resourse
使用这个注解时,会先根据byName查找,然后byType,都找不到时才会报错。
<bean id="cat1" class="com.klaus.pojo.Cat"/>
<bean id="cat" class="com.klaus.pojo.Cat"/>
public class People {
@Autowired
@Qualifier(value = "dog11")
private Dog dog;
@Resource
private Cat cat;
这时,程序可以运行,通过byName的方式。
<bean id="cat1" class="com.klaus.pojo.Cat"/>
public class People {
@Autowired
@Qualifier(value = "dog11")
private Dog dog;
@Resource
private Cat cat;
这时,程序也可以运行,通过byType的方式。
<bean id="dog11" class="com.klaus.pojo.Dog"/>
<bean id="dog111" class="com.klaus.pojo.Dog"/>
如果同样出现上面这种情况,使用@Resourse(name = "dog11")来指定。
public class People {
@Autowired
@Qualifier(value = "dog11")
private Dog dog;
@Resource(name = "cat1")
private Cat cat;
private String name;
...
}
下面是文档结构,个人感觉就是,IOC 容器会根据 People 里的类在beans.xml中已创建的实例中寻找对应的实例。寻找方总的来说有两种一是根据类名,二是根据类的种别,比如说Cat是一类,Dog是一类,如果同名的找不到,而同类型的又有很多个(如上面的 3 ),此时就要用特殊注解属性指定具体名称。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LBugCzAu-1627118636805)(https://gitee.com/man-ljw/PicBed/raw/master/6V@]93VA)][2IL5((FUVM0{T.png)
@Resource和@Autowired:
同:
- 都是用来自动装配的,都可以放在属性上
- @Autowired 通过byType的方式实现装配,要求该对象必须存在
- @Resource 默认通过byName,如果找不到名字,则通过byType实现。如果两个都找不到,则报错
异:
- @Autowired 通过byType的方式,@Resource 通过byName
使用注解开发
bean
@Component,放在类前
package com.klaus.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
public String name ;
public void setName(String name) {
this.name = name;
}
}
属性注入
@Value(“klaus”),放在属性前,或者属性的 set 方法前
package com.klaus.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
// 相当于 <property name="name" value="klaus"/>
// @Value("klaus")
public String name ;
@Value("klaus")
public void setName(String name) {
this.name = name;
}
}
@Component 衍生的注解
@Component有几个衍生注解,按mvc分为三层:
- dao层 [ @Repository ]
- service层 [ @Service ]
- controller层 [ @Controller ]
上述四个注解都是一样的、同级的,都是把某个类注册到Spring容器中,装配Bean。
自动装配
@Autowired
@Nullable
@Resource
作用域
@Scope("singleton") // 放在类前,还是
package com.klaus.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// 单例模式 ,相当于<bean id="user" class="com.klaus.pojo.User" scope="prototype" />
@Scope("singleton")
public class User {
public String name ;
@Value("klaus")
public void setName(String name) {
this.name = name;
}
}
小结
xml于注解:
- xml 适用范围更广。
- 注解维护更复杂
使用Java方式进行配置
完全不使用 Spring 的 xml 配置,全权交给 Java 做。
文件结构:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KiDM0i4s-1627118636807)(https://gitee.com/man-ljw/PicBed/raw/master/)]}]RV04GR6PCLKH5OXH{ZSB.png)
实体类 User.java
package com.klaus.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 这个类注册到容器中,被Spring接管
@Component
public class User {
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
// 属性注入
@Value("klaus")
public void setName(String name) {
this.name = name;
}
}
配置类 MyConfigure.java
package com.klaus.configure;
import com.klaus.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
// 代表这是一个配置类,本身就是一个组件
// 和之前的 beans.xml 一样
@Configuration
@ComponentScan("com.klaus.pojo")
// 把MyConfig2里的配置导入
@Import(MyConfig2.class)
public class MyConfigure {
// 相当于之前的 <bean />
// 方法名字等于之前的 id,方法的返回值就是 bean 中class属性
@Bean
public User getUser(){
return new User();
}
}
配置类MyConfig2.java
package com.klaus.configure;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig2 {
}
测试类 MyTest.java
import com.klaus.configure.MyConfigure;
import com.klaus.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
// 如果完全使用配置方式去做,只能通过 AnnotationConfigApplicationContext 获取容器
// 通过配置类的 class 加载
ApplicationContext context =
new AnnotationConfigApplicationContext(MyConfigure.class);
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser);
}
}
本文来自博客园,作者:klaus08,转载请注明原文链接:https://www.cnblogs.com/klaus08/p/15104981.html

浙公网安备 33010602011771号