-
什么是 Spring ?
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。简单点来说Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器。
-
IOC(控制反转)和DI(依赖注入)
IOC:也即控制反转,DI即依赖注入,控制反转IOC和依赖注入DI其实就是同个概念的两个不同角度的解释。 控制反转可以理解为获取依赖对象的控制反转过来。有反转的概念自然就有正转的概念。若有两个类,类A和类B,若类A依赖与类B,则类A要获取类B的方法,这时我们可以按照传统的JavaSE思想,在A类里,写代码B b = new B();
通过new关键字获取A类的依赖对象,或者通过工厂模式进行获取,当然还有等等其它方法。这些方法,就属于正转的方法,因为A类获取B类就是通过主动的方法进行获取的,统称为正转的方法。
然后,什么是反转呢?既然正转是主动的方式,那么反转就是被动的方式。也即我们要获取某个类的依赖对象,不需要类主动去获取。然后在Spring框架里是怎么实现的呢?在Spring框架里,实现IOC,是通过IOC容器实现的,由IOC容器负责创建和获取依赖对象,对象只是被动地接受依赖对象。
比如我们要在一个客户端类里获取用户信息类,下图给出正转的方式
有了IOC容器之后,获取依赖对象的方式就变成如图所示了
IOC是一种很好的解耦合思想,下面示意图
-
第一个Spring程序
1.导入Jar包(我这里利用maven , 他会自动下载对应的依赖项
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
2.编写一个Hello实体类
@Setter
@Getter
@ToString
@AllArgsConstructor
public class Hello {
private String Str;
}
3.编写我们的spring文件 , 我命名为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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--bean就是java对象 , 由Spring创建和管理-->
<!-- 以前我们这样创建对象Hello hello = new Hello();-->
<!-- 这里的id就类似于前面代码的hello,class的值就类似于前面代码的Hello()-->
<bean id="Hello" class="top.yunhuisu.pojo.Hello">
<property name="str" value="HelloSpring"/>
</bean>
</beans>
4.上面的三步做好我们就可以进行测试了
@Test
public void testHello() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) applicationContext.getBean("Hello");
System.out.println(hello.toString());
}
-
当实体类里面出现有参构造方法这样来创建
1.这是一个有参构造的实体类
@Setter
@Getter
@ToString
@AllArgsConstructor
public class Hello {
private String Str;
}
2.applicationContext.xml 有三种方式编写(constructor-arg标签)
<bean id="Hello" class="top.yunhuisu.pojo.Hello">
<!-- 第一种根据参数名字设置,这是常用的一种 -->
<!-- name指参数名 -->
<constructor-arg name="Str" value="Hello"/>
</bean>
<bean id="Hello" class="top.yunhuisu.pojo.Hello">
<!-- 第二种根据index参数下标设置 -->
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="HelloSpring"/>
</bean>
<bean id="Hello" class="top.yunhuisu.pojo.Hello">
<!-- 第三种根据参数类型设置 -->
<constructor-arg type="java.lang.String" value="HelloSpring"/>
</bean>
-
Spring配置
1.别名(有二种方式给bean中的id取别名,第一种比较好用)
<!-- id是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
如果配置id,又配置了name,那么name是别名第一种采用name属性,
可以设置多个别名,可以用逗号,分号,空格隔开-->
<!--如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象-->
<bean id="Hello" class="top.yunhuisu.pojo.Hello" name="hello1 hello2,hello3;newHello">
<property name="str" value="HelloSpring"/>
</bean>
<!--第二种采用alias设置别名,为bean设置别名,可以设置多个别名-->
<alias name="Hello" alias="hello"/>
<alias name="Hello" alias="hello1"/>
2.import团队的合作通过import来实现 (将多个applicationContext合到一个,使用的时候就使用总的那个applicationContext)
<import resource="{path}/applicationContext1.xml"/>
-
依赖注入(DI)之Set 注入,构造器注入上面讲过
编写测试pojo类 :
Address.java类
@Setter
@Getter
public class Address {
private String address;
}
Student.java类
@Setter
@Getter
public class Student {
private String Name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String, Object> car;
private Set<String> games;
private String wife;
private Properties properties;
@Override
public String toString() {
return "Student{" +
"Name='" + Name + '\'' +
", address=" + address.getAddress() +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", car=" + car +
", games=" + games +
", wife='" + wife + '\'' +
", properties=" + properties +
'}';
}
}
1、常量注入
<bean id="address" class="top.yunhuisu.pojo.Address">
<property name="name" value="大阳光海盗"/>
</bean>
2、Bean注入
注意:这里的值是一个引用,ref
<bean id="address" class="top.yunhuisu.pojo.Address">
<property name="address" value="四川"/>
</bean>
<bean id="student" class="top.yunhuisu.pojo.Student">
<property name="address" ref="address"/>
</bean>
3、数组注入
<bean id="address" class="top.yunhuisu.pojo.Address">
<property name="books">
<array>
<value>Java成神之路</value>
<value>浅谈Spring</value>
</array>
</property>
</bean>
4、List注入
<bean id="student" class="top.yunhuisu.pojo.Student">
<!--List注入-->
<property name="hobbys">
<list>
<value>音乐</value>
<value>写代码</value>
<value>赛车</value>
</list>
</property>
</bean>
5、Map注入
<bean id="student" class="top.yunhuisu.pojo.Student">
<!--Map集合注入-->
<property name="car">
<map>
<entry key="学生卡" value="10001"/>
<entry key="银行卡" value="637849039400"/>
<entry key="饭卡" value="158539"/>
</map>
</property>
</bean>
6、set注入
<bean id="student" class="top.yunhuisu.pojo.Student">
<!--Set注入-->
<property name="games">
<set>
<value>LOL</value>
<value>王者荣耀</value>
</set>
</property>
</bean>
7、Null注入
<bean id="student" class="top.yunhuisu.pojo.Student">
<!--Null注入-->
<property name="wife">
<null/>
</property>
</bean>
8、Properties注入
<bean id="student" class="top.yunhuisu.pojo.Student">
<!-- Properties注入-->
<property name="properties">
<props>
<prop key="性别">男</prop>
<prop key="年龄">20</prop>
</props>
</property>
</bean>
测试:
@Test
public void testStudent() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student.toString());
}
测试结果
-
P命名和C命名空间的注入(扩展):
编写User类:
@Setter
@Getter
@ToString
public class User {
private String Name;
private String Age;
}
1.第一步在beans里面写C或者P的约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
2.P命名空间的使用:
<!--这是没有构造方法的时候-->
<bean id="user" class="top.yunhuisu.pojo.User" p:name="大阳光" p:age="18"></bean>
3.P命名空间的使用:
<!--这是有构造方法的时候,也就是在User类上面加上@AllArgsConstructor注解-->
<bean id="user" class="top.yunhuisu.pojo.User" c:Name="大阳光" c:Age="18"></bean>
测试:
@Test
public void testUser() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.toString());
}
-
Bean的作用域:
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。 |
application | 限定一个Bean的作用域为ServletContext 的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。 |
-
单例模式的使用(默认就是单例):
<!--设置scope属性为singleton即可显示单例-->
<bean id="user" class="top.yunhuisu.pojo.User" c:Name="大阳光" c:Age="18" scope="singleton"></bean>
单例测试(取二次同样的bean判断是True):
@Test
public void testUser() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
User user2 = (User) applicationContext.getBean("user");
System.out.println(user==user2); // true
}
-
原型模式的使用:
<!--设置scope属性为prototype即可-->
<bean id="user" class="top.yunhuisu.pojo.User" c:Name="大阳光" c:Age="18" scope="prototype"></bean>
单例测试(取二次同样的bean判断是False):
@Test
public void testUser() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) applicationContext.getBean("user");
User user2 = (User) applicationContext.getBean("user");
System.out.println(user==user2); // false
}
-
Bean的自动装配(bean的autowir属性):
建一个Cat和Dog类,以及person类:
Dog.java类
public class Dog {
public void Eat() {
System.out.println("狗吃骨头");
}
}
Cat.java类
public class Cat {
public void Eat() {
System.out.println("猫吃鱼");
}
}
Person类.java
@Setter
@Getter
@ToString
public class Person {
private Cat cat;
private Dog dog;
private String Name;
}
byType装配:
<bean id="cat" class="top.yunhuisu.pojo.Cat"/>
<bean id="Dog" class="top.yunhuisu.pojo.Dog"/>
<!-- byName是通过id来找的,id要和set后面的一致,不然报错,id还要唯一-->
<!-- byType是通过类型来找的-->
<bean id="person" class="top.yunhuisu.pojo.Person" autowire="byType">
<property name="name" value="大阳光"/>
</bean>
测试代码:
@Test
public void testByType() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = applicationContext.getBean("person", Person.class);
person.getCat().Eat();
person.getDog().Eat();
}
使用注解自动装配:
导入约束:
<?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>
注解的使用:
<bean id="cat2" class="top.yunhuisu.pojo.Cat"/>
<bean id="dog" class="top.yunhuisu.pojo.Dog"/>
<bean id="dog" class="top.yunhuisu.pojo.Person"/>
在类的属性或者set方法上面加上@Autowired,当加上这个可以不用写set方法了
其中@Qualifier("XXX")可以自定义id标识
@Setter
@Getter
@ToString
public class Person {
@Autowired
@Qualifier("cat2")
private Cat cat;
@Autowired
private Dog dog;
private String Name;
}
测试代码:
@Test
public void testByType() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Annotation.xml");
Person person = applicationContext.getBean("person", Person.class);
person.getCat().Eat();
person.getDog().Eat();
}
-
Spring注解开发:
引入配置文件
<?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:component-scan base-package="top.yunhuisu"/>
<context:annotation-config/>
</beans>
编写类User.java
@Component
@Setter
@Getter
/*@Component类似于<bean id="user" class="top.yunhuisu.pojo.User"/>,也可以写在set方法上面*/
@Scope("prototype")
/*Scope是bean的作用域*/
public class User {
@Value("大阳光")
/*Value类似于<property name="name" value="大阳光"/>*/
private String Name;
}
测试:
@Test
public void testAnno() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Annotation.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user.getName());
}
衍生注解:
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
@Controller:web层
@Service:service层
@Repository:dao层
Javaconfig代替xml注解开发:
编写User类User.java
@Component
public class User {
@Value("大阳光")
private String Name;
@Override
public String toString() {
return "User{" +
"Name='" + Name + '\'' +
'}';
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
编写config类ConfigUtils.java
@Configuration
/*扫描包的注解*/
@ComponentScan("top.yunhuisu")
/*类似于xml的导包合成一个*/
@Import(bean2.class)
public class ConfigUtlis {
@Bean("user")
@Scope("prototype")
public User getUser() {
return new User();
}
}
测试类tsetConfig.java:
public class testConfig {
@Test
public void testConfig() {
Object object;
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigUtlis.class);
User user = applicationContext.getBean("user", User.class);
System.out.println(user.toString());
}
}