Spring学习
Spring概念
- 轻量级的控制反转(IOC)和面向切面编程(AOP)框架
- 导入jar包【spring-webmvc比较全】
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
IOC理论推导
- 例子在笔记上
- 核心思想:提供set方法实现动态实现值的注入
HelloSpring实现
- 实现类
- 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="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
</beans>
- 测试类
ApplicationContext context =
new ClassPathXmlApplicationContext("XXX.xml", "XXX.xml");
//getBean的两种方式 *user为xml中的id的值*
user name = (user) context.getBean("user");
user name = context.getBean("user",User.class);
核心思想
- 所有的类都需要装配到bean.xml中
- 所有的Bean都需要通过容器里去取
- 容器中取出来的Bean是一个对象,可以直接使用
依赖注入 Dependency injection (DI)
解决的问题:对象是由Spring创建的,对象的属性是由Spring容器设置的,如何实现?
在Spring中有Bean三种装配的方式:
**在xml中显示的配置**
在java中显示的配置
隐式的自动装配bean
1.构造器注入
通过无参构造方法来实现
<property name="name" value="spri ngliang"/>
通过有参构造方法来实现[三种]
<constructor-arg name="name" value="Spring"/>
<constructor-arg index="0" value="Spring"/>
<constructor-arg type="java.lang.String" value="Spring"/>
2.set注入
常量注入/Bean注入/数组注入/List注入/Map注入/set注入/Null注入/Properties注入
3.p命名空间注入
导入约束 : xmlns:p="http://www.springframework.org/schema/p"
<!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.liang.pojo.User" p:name="梁宝" p:age="18"/>
4.c命名空间注入
导入约束 : xmlns:c="http://www.springframework.org/schema/c"
<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
<bean id="user" class="com.liang.pojo.User" c:name="梁宝" c:age="18"/>
Spring配置
别名
Bean的配置【id/class/name/value…】
import
Bean的自动装配注解
在Spring中有Bean三种装配的方式:
在xml中显示的配置
在java中显示的配置
隐式的自动装配bean
自动装配是使用spring满足bean依赖的一种方法
Spring会在应用上下文中自动寻找,并自动给bean装配属性。
在xml中使用:
原本xml中的配置:
<bean id="user" class="com.kuang.pojo.User">
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="str" value="qinjiang"/>
</bean>
1.autowire byName (按名称自动装配)
<bean id="user" class="com.liang.pojo.User" autowire="byName">
<property name="str" value="Spring"/>
</bean>
2.autowire byType (按类型自动装配)
<bean id="user" class="com.liang.pojo.User" autowire="byType">
<property name="str" value="Spring"/>
</bean>
在类中使用:
使用注解的方式注入属性
1.在Spring配置文件中引入context文件头,并开启注解支持。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!--引入context文件头-->
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
<!--引入context文件头-->
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解支持-->
<context:annotation-config/>
<!--此类注解,只需在xml中导入id和class,无需在xml中设置属性-->
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
</beans>
2.@Autoewired
@Autowired是按类型自动转配的,不支持id匹配。
public class User {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
}
3.@Qualifier
@Autowired是根据类型自动装配的,在@Autowired不能自动装配上属性时,通@Qualifier(value=“XXX”)使用
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
4.@Resource【jdk的注释,jdk11已取消】
@Resource如有指定的name属性,先按该属性进行byName方式查找装配;
其次再进行默认的byName方式进行装配;如果没有成功则按照byType方式查找。
public class User {
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}
5.@Nullable
字段标记了这个注解,说明这个字段可以为null
//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;
使用注解开发
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
1.导入aop的包
2.配置文件中导入context约束,并开启注解支持。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!--引入context文件头-->
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
<!--引入context文件头-->
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解支持-->
<context:annotation-config/>
<!--使用注解开发,无需在xml中设置xml中导入id、class、属性,只需要指定注解扫描包-->
<!--指定注解扫描包-->
<context:component-scan base-package="com.liang.pojo"/>
</beans>
3.在指定包下编写类,增加注解
3.1Bean的实现 @Component
组件,放在类上,说明这个类被Spring管理了,即被Bean管理了。
@Component("user")//user为类名
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
public String name = "梁厉害";
}
3.2属性注入 @Value()
使用注解注入属性
可以不用提供set方法,直接在直接名上添加@value(“值”)
如果提供了set方法,在set方法上添加@value(“值”)
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
@Value("秦疆")
// 相当于配置文件中 <property name="name" value="秦疆"/>
public String name;
}
3.3作用域@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:原型模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收。
@Controller("user")
@Scope("prototype")
public class User {
@Value("梁宝")
public String name;
}
3.4衍生注解
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
- @Controller:web层
- @Service:service层
- @Repository:dao层
写上这些注解,就相当于将这个类交给Spring管理装配了!
Bean的自动装配注解
上一节有具体内容
基于Java的方式配置Spring
现在完全不使用Spring的配置文件,全权交给java来做。
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
使用
实体类
@Component //将这个类标注为Spring的一个组件,放到容器中!
@Component
public class User {
@Value("干饭王")//属性值注入
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置文件【配置类】
import com.liang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@component
//Configuration代表这是一个配置类,相当于之前的beans.xm1
@Configuration
//指定扫描的包
@ComponentScan("com.liang.pojo")
//导入其他配置类
@Import(myconfig2.class)
public class myconfig {
//注册一个bean ,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
//相当于<property id="user" class=com.liang.pojo.User>
@Bean
public User user(){
return new User();就是返回要注入到bean的对象!
}
}
测试类
@Test
public void tset1(){
//使用配置类操作,只能通过AnnotationConfigApplicationContext来获取容器
ApplicationContext context = new AnnotationConfigApplicationContext(myconfig.class);
User user = (User) context.getBean("user");
System.out.println(user);
}
AOP
AOP(Aspect Oriented Programming)意为:面向切面程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要
关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点(PointCut):切面通知 执行的 “地点”的定义。
连接点(JointPoint):与切入点匹配的执行点。
使用AOP织入,需要导入一个依赖包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
使用Spring实现Aop
首先编写我们的业务接口和实现类
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void search() {
System.out.println("查询用户");
}}
然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
public class Log implements MethodBeforeAdvice {
@Override
//method 要执行目标对象的方法
//args 参数
//target 目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
public class Afterlog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+target.getClass().getName()+"的"+method.getName()+"方法");
}
}
<!--注册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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="UserService" class="com.liang.service.UserServiceImpl"/>
<bean id="log" class="com.liang.log.Log"/>
<bean id="afterlog" class="com.liang.log.Afterlog"/>
<!--aop的配置-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法--execution要执行的位置-->
<aop:pointcut id="pointcut" expression="execution(* com.liang.service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法. pointcut-ref切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
自定义类来实现Aop
业务接口和实现类上面一样
编写增强类
public class diy {
public void after(){
System.out.println("========执行方法之前==========");
}
public void before(){
System.out.println("========执行方法之后==========");
}
}
最后去spring的文件中注册 和配置
头文件不再重复
<bean id="diy" class="com.liang.log.diy"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diypointcut" expression="execution(* com.liang.service.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="diypointcut" method="before"/>
<aop:after method="after" pointcut-ref="diypointcut"/>
</aop:aspect>
</aop:config>
使用注解实现
使用注解编写增强类
@Aspect
@Component
public class annotion {
@After("execution(* com.liang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("========执行方法之前==========");
}
@Before("execution(* com.liang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("========执行方法之后==========");
}
}
最后去spring的文件中注册 和配置
头文件不再重复
<bean id="annotion" class="com.liang.log.annotion"/>
<aop:aspectj-autoproxy/>
Spring整合Mybatis
MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。
导入jar包
<dependencies>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!--aspectJ AOP 织入器-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!--mybatis-spring整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
<!-- 配置Maven静态资源过滤问题! -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
编写配置文件
整合实现一
前期准备:实体类、实体类对应的接口、接口对应的配置文件[这几项和mybatis的一致,无需改动]
- 引入Spring配置文件beans.xml
【注意:此处可以将mybatis配置单独放在一个xml中,然后建立一个总的配置文件,通过import导入】
<?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">
<!--配置数据源替换mybaits的数据源-->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?
useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--配置SqlSessionFactory,关联MyBatis-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations"
value="classpath:com/liang/dao/*.xml"/>
</bean>
<!--注册sqlSessionTemplate,关联sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!--注册bean实现-->
<bean id="userDao" class="com.kuang.dao.UserDaoImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
. 增加Dao接口的实现类;私有化sqlSessionTemplate
public class UserMapperImpl implements UserMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> selectuser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectuser();
}
}
测试:
@Test
public void test2(){
ApplicationContext context = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper mapper = (UserMapper) context.getBean ("userMapper2");
List<User> user = mapper.selectuser();
System.out.println(user);
}
此时mybatis-config.xml为:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.liang.pojo"/>
</typeAliases>
</configuration>
整合实现二
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好。
修改:
- 将我们上面写的UserDaoImpl修改一下
//继承SqlSessionDaoSupport类
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
@Override
//无需使用set方法,直接调用getSqlSession()
public List<User> selectuser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectuser();
}
}
- 修改bean的配置
<bean id="userMapper2" class="com.liang.dao.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
声明式事务
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理 - 一般情况下比编程式事务好用。
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务式管理。
- 使用Spring管理事务,注意头文件的约束导入 : tx
并将aop约束导入
<?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:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
- JDBC事务管理器配置
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
- 配置事务的通知
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--所有方法都开启-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行
为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。【默认选择】
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
- propagation_required类似的操作
- 配置AOP
<aop:config >
<aop:pointcut id="txPoint" expression="execution(* com.liang.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
在xml配置文件中一次加入上面的配置,就完成了声明式事务的配置。
可以测试,一个方法中的几个步骤,要么都成功,要么都失败。
【需要实体类,实体类对应的接口、接口的实现类、mapper.xml文件、测试类、beans.xml】