Spring 4.x
文章目录
1. Spring Boot
Spring Boot用于快速开启一个Spring项目:
- 通过Maven方式新建一个项目
- pom.xml中指定parent为
spring-boot-starter-parent
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
- 依赖starter,书本p51-p52有介绍不同的starter,此处为了支持Web应用和数据库开发导入了
spring-boot-starter-web
和spring-boot-starter-jdbc
(connector-j需要另外导入,右键Diagrams显示依赖,可以看到依赖了什么库):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
- 定义Application,使用
@SpringBootApplication
代替@Configuration
、@ComponentScan
和@EnableAutoConfiguration
三个注解,@EnableTransactionManagement
表示支持事务,继承SpringBootServletInitializer
重写confiura()
方法以支持Spring MVC
@SpringBootApplication
@EnableTransactionManagement
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
}
- 在resource下创建application.properties,配置数据库链接、tomcat、jsp:
spring.datasource.url=jdbc:mysql://localhost:3306/sampledb?serverTimezone=GMT
spring.datasource.username=zhangyijun
spring.datasource.password=mysql1234
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.tomcat.max-idle=10
spring.datasource.tomcat.min-idle=8
spring.datasource.tomcat.max-wait=1000
spring.datasource.tomcat.max-active=100
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.validation-query=select 1
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
- 编写Controller,使用注解
@RestController
和@RequestMapping
:
@RestController
public class LoginController {
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
@RequestMapping(value = {
"/hello", "/index.html"})
public ModelAndView loginPage() {
return new ModelAndView("login");
}
@RequestMapping(value = "/loginCheck.html")
public ModelAndView loginCheck(HttpServletRequest request, LoginCommand loginCommand) {
boolean isValidUser = userService.hasMatchUser(loginCommand.getUserName(), loginCommand.getPassword());
if (!isValidUser) {
return new ModelAndView("login", "error", "用户名或密码错误");
} else {
User user = userService.findUserByUserName(loginCommand.getUserName());
user.setLastIp(request.getLocalAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
}
}
}
- 编写剩余代码,JdbcTemplate注入到Dao中,Dao注入到Service中,Service注入到Controller中
2. IoC容器
2.1 ApplicationContext
2.1.1 AnnotationConfigApplicationContext
- 拥有
@Bean
注解方法的类 User:
@Bean(name = "DefaultUser")
public User buildUser() {
return User.builder()
.userId(123)
.userName("in annotation @Bean")
.password("123")
.credits(123)
.lastIp("127.0.0.1")
.lastVisit(new Date())
.build();
}
- 通过构造器传入上面的类
- 使用
<T> T getBean(String name, Class<T> requiredType)
方法获取bean:
ApplicationContext context = new AnnotationConfigApplicationContext(User.class);
User user = context.getBean("DefaultUser", User.class);
2.1.2 ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
}
- 通过构造器传入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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="date" class="java.util.Date"/>
<bean id="user" class="com.smart.domain.User"
p:userId="1"
p:userName="in xml file: beans.xml"
p:password="asd"
p:credits="123"
p:lastIp="1.1.1.1"
p:lastVisit-ref="date"/>
</beans>
val context = new ClassPathXmlApplicationContext("classpath:beans.xml");
val user = context.getBean("user", User.class);
"classpath:beans.xml"
此处可以简写为"beans.xml"
beans.xml
放在了resources
文件夹下
2.2 生命周期
BeanFactory
和ApplicationContext
的生命周期类似,BeanFactory
在调用getBean(beanName)
的时候开始生命周期,ApplicationContext
在容器开启的时候一次性初始化所有Bean(可以通过@Lazy
注解实现懒加载):
- InstantiationAwareBeanPostProcessor#
postProcessBeforeInstantiation()
- 实例化
- InstantiationAwareBeanPostProcessor#
postProcessAfterInstantiation()
- InstantiationAwareBeanPostProcessor#
postProcessPropertyValues()
- 设置属性值
- BeanNameAware#
setBeanName()
- BeanFactoryAware#
setBeanFactory()
- BeanPostProcessor#
postProcessBeforeInitialization()
- InitializingBean#
afterPropertiesSet()
- init-method
- BeanPostProcessor#
postProcessAfterInitialization()
- scope
- singleton Spring缓存池中准备就绪的Bean
- prototype 将准备就绪的Bean交给调用者
- 容器销毁,调用DisposableBean中的
destroy()
方法 - destory-method
- 通过在
<bean>
标签中定义init-method
和destory-method
,因为对象实例化和属性初始化的原因,这两个方法的生命周期都比较靠后 - 通过注解
@PreDestroy
和@PostConstrut
修饰方法
3. 在IoC容器中装配Bean
3.1 Setter注入
- 需要提供对应的setter方法,并且id或name前两个字母要么都是大写,要么都是小写
public class User{
private String name;
public void setName(String name){
this.name = name;
}
}
<bean id="user" class="com.smart.domain.User" p:name="1"/>
3.2 Construct注入
- 最好用index+type指定入参
<bean id="user1" class="com.smart.domain.User">
<constructor-arg index="0" type="int" value="1"/>
<constructor-arg index="1" type="java.lang.String" value="1"/>
<constructor-arg index="2" type="java.lang.String" value="1"/>
<constructor-arg index="3" type="int" value="1"/>
<constructor-arg index="4" type="java.lang.String" value="1123"/>
<constructor-arg index="5" type="java.util.Date" ref="date"/>
</bean>
3.3 Factory注入
- 如果工厂提供静态方法,则把factory-bean换成class指定工厂类就行了
<bean id="userFactory" class="com.smart.factory.UserFactory"/>
<bean id="user" factory-bean="userFactory" factory-method="createUser"/>
<!--静态0-->
<bean id="user" class="com.smart.factory.UserFactory" factory-method="createUser"/>
3.4 内部Bean
- 作用域为prototype
<bean id="boss" class="com.smart.attr.Boss">
<property name="car">
<bean class="com.smart.attr.Car">
<property name="maxSpeed" value="200"/>
<property name="price" value="2000.00"/>
</bean>
</property>
</bean>
3.5 注入null
<bean id="boss" class="com.smart.attr.Boss">
<property name="car">
<null/>
</property>
</bean>
3.6 注入集合
- 可以引入util命名空间来显式指定实现类
<bean id="boss" class="com.smart.attr.Boss">
<!-- list/数组-->
<!--<property name="carList">-->
<!-- <list>-->
<!-- <value>ferrari</value>-->
<!-- <value>maserati</value>-->
<!-- <value>porsche</value>-->
<!-- </list>-->
<!--</property>-->
<!-- util命名空间指定list-->
<util:list id="carList" list-class="java.util.LinkedList">
<value>ferrari</value>
<value>maserati</value>
<value>porsche</value>
</util:list>
<!-- Set-->
<property name="carSet">
<set>
<value>ferrari</value>
<value>maserati</value>
<value>porsche</value>
</set>
</property>
<!-- Map-->
<property name="carMap"