1、Introduction of Spring
purpose:解决企业级开发的复杂性,整合了现有技术框架
SSH:Struct2+Spring+Hibernate
旧三大框架:SSH
Struts2:主要用于用户通过浏览器与后台程序进行交互。
Spring:主要是将一些主流的框架进行整合,方便程序员进行调用,能够较完美整合其他框架。
Hibernate:主要用于程序与数据库的交互。
SMM: SpringMVC+Spring+Mybatis
Spring 优点
开源免费框架
轻量级,非入侵式框架
控制反转(IOC),面向切面变成(AOP)
支持事务的处理,对框架整合的支持
Spring 缺点
配置地狱
Spring 7大模块
SpringBoot和SpringCloud必须掌握Spring和SpringMvc
Spring Boot
快速开发脚手架
可快速开发单个微服务
约定大于配置
Spring Cloud
基于SpringBoot实现
2、IOC
pom.xml中导入jar包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
传统设计:user调用service,service调用dao,主动性在user
IOC:user调用service,service掌握主动权(通过xml),service控制调用dao
IOC是一种通过描述(xml或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)
对象的属性由Spring容器设置,这个过程称为控制反转
控制:传统的对象是由程序本身控制创建的,使用Spring后,是由Spring来创建的
反转:程序本身不创建对象,变为被动接收对象
DI:利用set方法来进行注入
IOC是一种编程思想,由主动的编程变为被动的接受 (方法:newClassPathXmlApplicationContext)
总结:对象由Spring创建,管理,配置。
2.1配置IOC metadata
resource folder下新建xml(spring 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
插入多个bean来注册class,一个bean代表一个class
</beans>
2.2 DI
2.2.1 constructor-based DI
class中记得构造get和set方法
无参构造:默认,直接new。
public class MyTest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationcontext.xml");
UserServiceImple userServiceImple=(UserServiceImple) context.getBean("userserviceimpl");
userServiceImple.getUser();;
}
}
有参构造:
class例:
package x.y;
public class ThingOne {
public ThingOne(ThingTwo thingTwo, ThingThree thingThree) {
// ...
}
}
<beans>
<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"/>
</beans>
1st type DI (不推荐)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
2nd index DI
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
3rd name DI (常用)
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
总结:配置文件加载时,容器中管理对象都已经初始化。
2.2.2 setter-based DI
依赖:xml对象的创建依赖于容器
注入:xml对象中的所有属性
实例分析:
Address class
package com.jj;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address+ '\'' +
'}';
}
}
Student class
package com.jj;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobby;
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> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.toString() +
", books=" + Arrays.toString(books) +
", hobby=" + hobby +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
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 id="address" class="com.jj.Address">
<property name="address" value="杭州"/>
</bean>
<bean id="student" class="com.jj.Student">
<!-- 第一种,普通值注入 value-->
<property name="name" value="zhao"/>
<!-- 第二种,bean注入,ref-->
<property name="address" ref="address"/>
<!-- 数值注入-->
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>三国</value>
</array>
</property>
<!-- List-->
<property name="hobby">
<list>
<value>吃饭</value>
<value>睡觉</value>
<value>打游戏</value>
</list>
</property>
<!-- Map-->
<property name="card">
<map>
<entry key="身份证" value="123123123"/>
<entry key="银行卡" value="2334546677"/>
</map>
</property>
<!-- Set-->
<property name="games">
<set>
<value>LOL</value>
<value>PUBG</value>
<value>DNF</value>
</set>
</property>
<!-- null-->
<property name="wife">
<null/>
</property>
<!-- properties-->
<property name="info">
<props>
<prop key="No">2021025</prop>
<prop key="Sex">男</prop>
<prop key="token">root</prop>
<prop key="password">1234</prop>
</props>
</property>
</bean>
</beans>
注意:Address方法需构造toString(否则获取的值不是设定的值)
程序
import com.jj.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.swing.text.AbstractDocument;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Student student= (Student) context.getBean("student");
System.out.println(student);
}
}
结果
Student{name='zhao', address=Address{address='杭州'}, books=[西游记, 红楼梦, 三国], hobby=[吃饭, 睡觉, 打游戏], card={身份证=123123123, 银行卡=2334546677}, games=[LOL, PUBG, DNF], wife='null', info={No=2021025, Sex=男, password=1234, token=root}}
2.2.3 拓展(c/p)
xml配置
必须加上
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c">
<!-- p namespace,可以直接注入属性的值-->
<bean id="user" class="com.jj.User" p:age="18" p:name="zhao"/>
<!-- c namespace,需要构造有参构造方法,同时记得构造无参构造方法,否则报错-->
<bean id="user1" class="com.jj.User" c:age="18" c:name="bb"/>
</beans>
实例分析
User class
package com.jj;
public class User {
private int age;
private String name;
public User() {
}
public User(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
程序执行
import com.jj.Student;
import com.jj.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.swing.text.AbstractDocument;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context2=new ClassPathXmlApplicationContext("ApplicationContext2.xml");
User user= (User) context2.getBean("user1");
System.out.println(user);
}
}
运行结果
2.3 bean scope
浏览器翻译成中文,可以讲究看看
1.单例模式(spring默认)每次创建都是同一个对象 scope=“singleton"
2.原型模式:每次创建都是新对象scope="prototype"
3.request,session,application都在web开发中用到
3 Spring 配置
3.1 别名 (alias)
<bean id="user" class="xxxx"/>
<alias name="user" alias="uuuserrr"/>
3.2 bean
id:唯一标识符,相当于对象名
class:bean对象对应的全限定名:包名+类型 (com.jj.xxx)
name:也可以是别名,可以同时取多个
<property>下配置参数
<bean id="user" class="com.jj.xxx" name="user2 u1,u2;u3>
<property name="name" value="xxxxxx"/>
</bean>
3.3 import
团队开发使用,将多个配置文件,导入合并一个
<import resource="applicationContext1"/>
<import resource="applicationContext2"/>
<import resource="applicationContext3"/>
4 Bean的自动装配
自动装配式Spring满足bean依赖的一种方式
spring会自动上下文寻找。并自动给bean装配属性
在spring中有三种装配方式:
在xml中显示配置
在java中显示配置
隐式的自动装配bean(重要)
byName:自动在容器上下文查找和自己对象set方法后面的值对应的bean id
byType:自动在容器上下文查找和自己对象属性类型相同的bean
实例:
autowire="byName"
要保证bean id唯一,并且id值与对象set方法后面的值一样
<bean id="dog" class="com.jj.Dog"/>
<bean id="cat" class="com.jj.Cat"/>
<bean id="people" class="com.jj.People" autowire="byName">
<property name="name" value="zhao"/>
</bean>
autowire="byType"
保证class唯一,同一个class只能bean一个
<bean id="dog" class="com.jj.Dog"/>
<bean id="cat" class="com.jj.Cat"/>
<bean id="people" class="com.jj.People" autowire="byType">
<property name="name" value="zhao"/>
</bean>
使用注解实现自动装配
须知:
导入约束
配置注解的支持
<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
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
@Autowired 直接用在属性上,也可在set方法上使用
用了Autowired可以不用编写set方法,前提是自动装配的属性在IOC,且符合byname或者bytype
如果两个cat型不同名字的cat,可加@Qualifier(value=" ")来指定指向哪个
@Resource注解也可以,用法类似@Autowired
区别:
@Autowire默认通过byType,不满足则通过byName
@Resource相反
5.自动注解开发
5.1 前序准备:
aop包导入
约束导入
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/context/spring-aop.xsd">
<!-- 开启注解的支持-->
<context:annotation-config/>
<!-- 扫描包,包下的注解就会生效-->
<context:component-scan base-package="com.jj.pojo"/>
<!-- <bean id="user" class="com.jj.pojo.User"/>-->
</beans>
5.2 属性注入
package com.jj.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value("zhao")
public String name;
}
5.3 衍生的注解
@Component有几个衍生注解,这几个注解功能一样,代表将某个类注册到spring中,装配bean,我们在web开发中,按照mvc三层架构分层
dao :@Repository
service:@Service
controller:@Controller
5.4 作用域
@Scope(value = "singleton")
@Scope(value = "singleton")
总结:
xml比较万能,适用于任何场景!维护简单方便
注解不是自己的类使用不了,维护复杂
最佳实践:xml管理bean,注解只负责完成属性的注入
特别注意:如让注解生效,需要开启注解支持
6. 使用java的方式配置spring
javaconfig是spring的一个子项目,spring4后成为核心
实例
UserConfig class
package com.jj.config;
import com.jj.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;
//这里也会被spring容器托管,它本身也是一个@component
//@configuration代表只是一个配置类,类似applicationContext.xml
@Configuration
@ComponentScan("com.jj.pojo")
@Import(UserConfig2.class) //导入其他类,合并使用
public class UserConfig {
//注册bean,相当于在xml中写一个bean标签
//方法的名字,相当于bean中的id
//方法的返回值,相当于bean中的class
//<bean id="getUser" class="User"/>
@Bean
public User getUser(){
return new User(); //返回要注入到bean的对象
}
}
User class
package com.jj.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("zhao")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
执行程序
import com.jj.config.UserConfig;
import com.jj.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(UserConfig.class);
User user= (User) context.getBean("getUser");
System.out.println(user.getName());
}
}
结果
注意:
new context的时候使用的是AnnotationConfigApplicationContext,括号内要填写索要引用class的class,例如:UserConfig.class
7.代理模式
7.1静态代理
一般有以下角色,以房东出租房,房客承租房为例:
抽象角色:一般用接口或者抽象类,出租房视为一个抽象接口
真实角色:被代理的角色,房东视为想要出租房的真实角色
代理角色:代理真实角色,一般会做一些附属操作,中介视为代理对象
客户:访问代理对象的人,房客视为客户
代理模式优点:
真实角色操作更纯粹,不用关注一些公共业务
公共业务交给代理,实现业务分工
公共业务扩展方便集中管理
缺点:
每个真实角色都会产生一个代理角色,代码量多,效率低
编写代码步骤:
1.出租的接口
package com.jj.demo01;
//出租房,抽象一般用接口
public interface Rent {
void rent();
}
2.真实角色,房东继承出租接口
package com.jj.demo01;
public class Host implements Rent{
@Override
public void rent() {
System.out.println("我是房东");
}
}
3.代理角色,代理也要继承出租接口
package com.jj.demo01;
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent(){
host.rent();
}
}
4.客户访问代理
package com.jj.demo01;
public class Client {
public static void main(String[] args) {
Proxy proxy=new Proxy(new Host());
proxy.rent();
}
}
代理的作用:比如纵向流程已开发全部可用,现在要在service增删改,但不希望破坏原有流程的所有东西,则使用代理来代理service实现不改动源代码而做修改
7.2 动态代理
与静态代理的角色一样
动态代理的代理类是动态生成的,不直接写好
动态代理分为两大类:
基于接口的动态代理--JDK动态代理
基于类--cglib
java字节码实现--javasist
动态代理重要类:Proxy,InvocationHandler(调用处理程序)
动态代理这节有点难理解,听了没太懂,我准备专门整理一章来记录我的理解。
如果有对动态代理有独特理解的大神,欢迎评论区指导。