1.Spring
Spring是一个轻量级的控制反转(IOC),面向切面编程(AOP)的整合框架!
1.1简介
- Spring:春天 可以理解为软件行业迎来了春天
- Spring框架是由于软件开发的复杂性而创建的
- Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情
- Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
- 2002年,首次退出了Spring框架的雏形,interface21
- 2004年3月24日这一天,Spring Framework 1.0 final 框架以interface21为基础正式出现在我们的视野中
1.2设计哲学
当您了解框架时,不仅要了解框架的工作而且要遵循的原则很重要。以下是 Spring 框架的指导原则:
- 提供每个级别的选择。 Spring 使您可以尽可能推迟设计决策。例如,您可以在不更改代码的情况下通过配置切换持久性提供程序。对于许多其他基础架构问题以及与第三方 API 的集成也是如此。
- 适应不同的观点。 Spring 拥有灵 Active,并且对如何完成工作一无所知。它从不同的角度支持广泛的应用程序需求。
- 保持强大的向后兼容性。对 Spring 的 Developing 进行了精心 Management,以使各个版本之间几乎没有重大更改。 Spring 支持精心选择的 JDK 版本和第三方库,以方便维护依赖于 Spring 的应用程序和库。
- 关心 API 设计。 Spring 团队投入了大量的思想和时间来制作直观,并在许多版本和很多年中都适用的 API。
- 为代码质量设置高标准。 Spring 框架非常强调有意义,最新和准确的 javadoc。它是极少数可以声明干净代码结构且程序包之间没有循环依赖关系的项目之一。
1.3下载地址
官网:https://spring.io/
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub下载地址:https://github.com/spring-projects/spring-framework/releases
maven依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
1.4Spring优点
- 它是一个开源的免费的框架(容器)
- 轻量级,非入侵式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理对框架整合的支持,大杂烩
2.IOC理论推导
1.Dao接口
package com.ljl.dao;
public interface UserDao {
int query();
}
2.DaoImpl
package com.ljl.dao;
public class UserDaoImpl implements UserDao {
public int query() {
System.out.println("进入mysql方法");
return 0;
}
}
3.Service接口
package com.ljl.service;
public interface UserService {
int query();
}
4.ServiceImpl
package com.ljl.service;
import com.ljl.dao.OraclImpl;
import com.ljl.dao.UserDao;
import com.ljl.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
UserDao userDao ;
public int query() {
userDao = new OraclImpl();
userDao.query();
return 0;
}
}
5.测试
import com.ljl.service.UserService;
import com.ljl.service.UserServiceImpl;
import org.junit.Test;
public class MyTest {
@Test
public void query(){
UserService userService = new UserServiceImpl();
userService.query();
}
}
在我们之前的业务中可能会需要根据用户的需求去更改源代码!如果程序代码量十分大,修改一次代码的成本代价十分昂贵
我们在使用set接口后,程序发生了革命性的变化
private UserDao userDao ;
//利用set方法实现动态值得注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序主动创建对象!控制权在程序员手上
- 使用set注入后,程序不再具有主动性,而是被动地接受对象
这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建,系统的耦合性大大降低,可以更加专注在业务的事项上!这就是IOC的原型!
3.HelloSpring
3.1配置元数据
如上图所示,Spring IoC 容器使用一种形式的配置元数据。此配置元数据表示您作为应用程序开发人员如何告诉 Spring 容器实例化,配置和组装应用程序中的对象。
传统上,配置元数据以简单直观的 XML 格式提供,这是本章大部分内容用来传达 Spring IoC 容器的关键概念和功能的内容。
Note
基于 XML 的元数据不是配置元数据的唯一允许形式。 Spring IoC 容器本身与实际写入此配置元数据的格式完全脱钩。如今,许多开发人员为自己的 Spring 应用程序选择Java-based configuration。
有关在 Spring 容器中使用其他形式的元数据的信息,请参见:
- Annotation-based configuration:Spring 2.5 引入了对基于注解的配置元数据的支持。
- Java-based configuration:从 Spring 3.0 开始,Spring JavaConfig 项目提供的许多功能成为了核心 Spring Framework 的一部分。因此,您可以使用 Java 而不是 XML 文件来定义应用程序类外部的 bean。要使用这些新功能,请参见@Configuration,@Bean,@Import和@DependsOn注解。
Spring 配置由容器必须 Management 的至少一个(通常是一个以上)bean 定义组成。基于 XML 的配置元数据将这些 bean 配置为顶级<beans/>
元素内的<bean/>
元素。 Java 配置通常在@Configuration
类中使用@Bean
注解的方法。
这些 bean 定义对应于组成应用程序的实际对象。通常,您定义服务层对象,数据访问对象(DAO),表示对象(例如 Struts Action
实例),基础结构对象(例如 Hibernate SessionFactories
,JMS Queues
等)。通常,不会在容器中配置细粒度的域对象,因为 DAO 和业务逻辑通常负责创建和加载域对象。但是,您可以使用 Spring 与 AspectJ 的集成来配置在 IoC 容器的控制范围之外创建的对象。参见使用 AspectJ 与 Spring 依赖注入域对象。
以下示例显示了基于 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">
<beans>
<bean id="helloSpring" class="com.ljl.pojo.HelloSpring">
<property name="name" value="darling"/>
<property name="age" value="21"/>
</bean>
</beans>
</beans>
- (1)
id
属性是标识单个 bean 定义的字符串。 - (2)
class
属性定义 bean 的类型并使用完全限定的类名。
id
属性的值是指协作对象。在此示例中未显示用于引用协作对象的 XML。有关更多信息,请参见Dependencies。
3.2实例化容器
提供给ApplicationContext
构造函数的位置路径是资源字符串,这些资源字符串使容器可以从各种外部资源(例如本地文件系统,Java CLASSPATH
等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
3.3测试
import com.ljl.pojo.HelloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test() {
// 获得管理对象的全局变量
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 通过Spring获取对象
HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring");
System.out.println(helloSpring.toString());
}
}
做完这一系列测试后我们就能对IOC有了一定的了解,到了现在我们应对不同的需求就不要去更改代码,只需要在xml文件中更改配置,所谓的IOC一句话表示:对象的创建,管理,装配都由Spring来操作.
4.Spring配置
4.1别名
<!-- 别名 ,起了别名就可以通过别名也能获取到对象-->
<alias name="helloSpring" alias="helloSpring2"/>
HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring2");
4.2Bean的配置
<!-- id :Bean的唯一标识符 我们通过id名才可以获取对象-->
<!-- class:Bean对象对应的全限定名:包名+类名-->
<!-- name: 也相当于给Bean取别名 还可以同时取多个 所以可以不用使用别名标签 -->
<!-- scope:作用域 默认单例模式创建对象-->
<bean id="helloSpring" class="com.ljl.pojo.HelloSpring" name="helloSpring3,helloSpring4" >
<constructor-arg name="name" value="小林"/>
<constructor-arg name="age" value="25"/>
</bean>
4.3import
import一般用于团队开发使用,它可以将多个配置文件,导入合并为一个
假设这个项目有多个人开发,可以将每个人的不同beans.xml导入到一个总的applicationContext.xml里面,使用时就可以只使用这一个总的配置文件即可
<import resource="beans.xml" />
5.依赖注入(DI)
5.1set注入
常用注入方式
5.1.1环境搭建
1.两个实体类
package com.ljl.pojo;
import java.util.*;
public class Student {
private String name;
private Adress adress;
private List<String> hobbis;
private Map<String,String> couple;
private Set<String> card;
private String [] books;
private String girlFriend;
private Properties info;
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public String getGirlFriend() {
return girlFriend;
}
public void setGirlFriend(String girlFriend) {
this.girlFriend = girlFriend;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Adress getAdress() {
return adress;
}
public void setAdress(Adress adress) {
this.adress = adress;
}
public List<String> getHobbis() {
return hobbis;
}
public void setHobbis(List<String> hobbis) {
this.hobbis = hobbis;
}
public Map<String, String> getCouple() {
return couple;
}
public void setCouple(Map<String, String> couple) {
this.couple = couple;
}
public Set<String> getCard() {
return card;
}
public void setCard(Set<String> card) {
this.card = card;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", adress=" + adress.toString() +
", hobbis=" + hobbis +
", couple=" + couple +
", card=" + card +
", books=" + Arrays.toString(books) +
", girlFriend='" + girlFriend + '\'' +
", info=" + info +
'}';
}
}
package com.ljl.pojo;
public class Adress {
private String adress;
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "Adress{" +
"adress=" + adress +
'}';
}
}
5.1.2编写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="adress" class="com.ljl.pojo.Adress">
<property name="adress" value="四川巴中"/>
</bean>
<bean id="student" class="com.ljl.pojo.Student" >
<property name="name" value="darling"/>
<property name="adress" ref="adress" >
</property>
<property name="hobbis">
<list>
<value>games</value>
<value>football</value>
<value>code</value>
</list>
</property>
<property name="couple">
<map>
<entry key="fat" value="Lsr"></entry>
<entry key="ljl" value="Lsr"></entry>
<entry key="lm" value="cz"></entry>
</map>
</property>
<property name="card">
<set>
<value>银行卡</value>
<value>身份证</value>
<value>学生证</value>
</set>
</property>
<property name="books" >
<array>
<value>英语书</value>
<value>数学书</value>
<value>Java书</value>
</array>
</property>
<property name="girlFriend" value=""/>
<property name="info">
<props>
<prop key="driver">com.oracle.deploy</prop>
<prop key="url">jdbc:mysql:localhost:3306//mybatisUserSSL=trueUseEncodingChacter=utf8</prop>
<prop key="user">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
5.1.3测试
import com.ljl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println(student.toString());
/**
* Student{
* name='darling',
* adress=Adress{adress=四川巴中},
* hobbis=[games, football, code],
* couple={fat=Lsr, ljl=Lsr, lm=cz},
* card=[银行卡, 身份证, 学生证],
* books=[英语书, 数学书, Java书], girlFriend='',
* info={
* user=root,
* password=123456,
* url=jdbc:mysql:localhost:3306//mybatisUserSSL=trueUseEncodingChacter=utf8,
* driver=com.oracle.deploy
* }
* }
*/
}
}
5.2Bean的作用域
Scope | Description |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
- 单例模式(Spring默认机制)
<bean id="student" class="com.ljl.pojo.Student" scope="singleton" >
- 原型模式(手动设置)
<bean id="student" class="com.ljl.pojo.Student" scope="prototype" >
- 其余的主要在运用在Web应用中
6.Bean的自动装配
-
自动装配是Spring满足bean依赖的一种方式
-
Spring会在上下文中自动寻找,并自动给bean装配属性
Spring中有三种装配方式
- 在xml中显示的配置
- 在java中显示配置
- 隐式的自动装配bean[重要]
6.1测试
<?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 class="com.ljl.pojo.Dog"/>
<bean class="com.ljl.pojo.Tiger"/>
<bean id="people" class="com.ljl.pojo.People" autowire="byType">
<property name="name" value="大林"/>
<!-- <property name="dog" ref="dog"/>-->
<!-- <property name="tiger" ref="tiger"/>-->
</bean>
</beans>
import com.ljl.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getDog().shout();
people.getTiger().shout();
}
}
6.2使用注解实现自动装配
jdk1.5支持的注解,spring2.5支持的注解
- 注解 在声明中提供了很多上下文,从而使配置更短,更简洁
- XML 擅长连接组件而不接触其源代码或重新编译它们。一些开发人员更喜欢将布线放置在靠近源的位置,而另一些开发人员则认为带注解的类不再是 POJO,而且,该配置变得分散且难以控制。
- 无论选择如何,Spring 都可以容纳两种样式,甚至可以将它们混合在一起。值得指出的是,通过其JavaConfig选项,Spring 允许以非侵入方式使用 注解,而无需接触目标组件的源代码,并且就工具而言,Spring 工具套件支持所有配置样式。
6.2.1使用注解环境搭建
- 导入约束:context约束
- 配置注解的支持: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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
6.2.2@Autowired
直接在属性上使用,也可以在set方法上使用
@Autowired
public void setDog(Dog dog) {
this.dog = dog;
}
@Autowired
public void setTiger(Tiger tiger) {
this.tiger = tiger;
}
6.2.3@Qualifier
当@Autowired装配环境复杂时,即无法通过这一个注解完成自动装配时,我们可以借助@Qualifier(value=“xxx”)来配合使用指定唯一的bean值注入问题
<bean id="dog111" class="com.ljl.pojo.Dog"/>
<bean id="dog1111" class="com.ljl.pojo.Dog"/>
<bean id="tiger11" class="com.ljl.pojo.Tiger"/>
<bean id="tiger111" class="com.ljl.pojo.Tiger"/>
@Autowired
@Qualifier(value = "dog1111")
public void setDog(Dog dog) {
this.dog = dog;
}
@Autowired
@Qualifier(value="tiger111")
public void setTiger(Tiger tiger) {
this.tiger = tiger;
}
6.2.4@Resource(建议使用)
用法类似于@Qualifier和@Autowired配合在一起使用,可以自动装配,还能通过那么属性寻找唯一的bean值注入
@Resource(name="dog1111")
public void setDog(Dog dog) {
this.dog = dog;
}
@Resource(name="tiger111")
public void setTiger(Tiger tiger) {
this.tiger = tiger;
}
7.使用注解开发
1.bean
@Component
public class User {
2.属性如何注入
@Value("大林")
private String name;
3.衍生的注解
这三个注解用法类似于实体类的@Conponent 只是为了规范化做了每个类用不同的注解名
- dao
@Repository
public class UserDao {
- service
@Service
public class UserService {
}
- controller
@Controller
public class UserController {
}
4.自动装配注解
前面个讲过了
5.作用域
@Scope(value = "singeltod")
public class User {
6.小结
xml与注解:
- xml更加万能,适用于任何场合,更易于维护
- 注解不是自己的类用不了,维护相对负责
xml与注解最佳实践:
- xml用来管理bean
- 注解用来属性的注入
- 使用过程中只需要注意必须让注解生效
8.代理模式
代理模式就是springAOP的底层
代理模式分类:
-
静态代理
-
动态代理
9.AOP
9.1SpringAPI接口实现AOP
<!--<!–配置Bean–>-->
<bean id="userServiceImpl" class="com.ljl.service.UserServiceImpl"/>
<bean id="afterLog" class="com.ljl.log.AfterLog"/>
<bean id="beforeLog" class="com.ljl.log.BeforeLog"/>
<!--<!– 方式一:原生SpringAPI–>-->
<!--<!–aop配置–>-->
<aop:config>
<!--<!– 切入点 expression:表达式 execution(要执行的位置) :修饰符 返回值 类名 方法名 参数–>-->
<aop:pointcut id="pointcut" expression="execution(* com.ljl.service.UserServiceImpl.*(..) )"/>
<!--<!– 环绕执行–>-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
9.2自定义类实现AOP
<bean id="diyPointCut" class="com.ljl.diy.DiyPointCut"/>
<bean id="userServiceImpl" class="com.ljl.service.UserServiceImpl"/>
<!-- 方拾二:自定义类-->
<aop:config>
<!-- 自定义切面 ref:要应用的类-->
<aop:aspect ref="diyPointCut">
<!-- 切入点 expression:表达式 execution(要执行的位置) :修饰符 返回值 类名 方法名 参数-->
<aop:pointcut id="point" expression="execution(* com.ljl.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
9.3使用注解实现AOP
<!-- 方式三:使用注解实现AOP-->
<context:component-scan base-package="com.ljl"/>
<context:annotation-config></context:annotation-config>
<aop:aspectj-autoproxy />
package com.ljl.anno;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class annotationAOP {
@Before("execution(* com.ljl.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("===执行方法前===");
}
@After("execution(* com.ljl.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("===执行方法后===");
}
}
10.整合Mybatis
步骤:
1.导入相关jar包
- junit
- mysql
- mybatis
- spring
- aop织入
- mybatis-spring【new】
2.编写配置文件
3.测试
10.1Mybatis-Spring
11.声明式事务
11.1
11.2Spring中的事务管理
- 声明式事务:AOP(常用)
- 编程式事务:代码中进行事务的管理
配置事务的原因:
- 如果不配置事务,可能存在数据提交不一致的情况
- 如果我们不在Spring中配置声明式事务,就需要在代码中手动声明事务
- 事务在项目开发中十分重要,涉及到数据库的一致性和完整性问题,不容马虎!
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务-->
<tx:attributes>
<tx:method name="add"/>
<tx:method name="deleteUser"/>
<!-- 所有方法加事务 propagation:传播 即事务的传播特性 默认REQUIRED-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 结合AOP实现事务的织入-->
<aop:config>
<!-- 配置事务切入点-->
<aop:pointcut id="txPointcut" expression="execution(* com.ljl.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- -->
事务在项目开发中十分重要,涉及到数据库的一致性和完整性问题,不容马虎!
```xml
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
<!-- 配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务-->
<tx:attributes>
<tx:method name="add"/>
<tx:method name="deleteUser"/>
<!-- 所有方法加事务 propagation:传播 即事务的传播特性 默认REQUIRED-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 结合AOP实现事务的织入-->
<aop:config>
<!-- 配置事务切入点-->
<aop:pointcut id="txPointcut" expression="execution(* com.ljl.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- -->