第一个spring
1. 新建maven 导入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
2. 编写对应类
package top.wmgx.spring;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Address address;
private String sex;
private int[] grade;
private List<Integer> list;
private Map<String,Integer> map;
private Properties properties;
}
package top.wmgx.spring;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
private String name;
}
3. 配置文件中注入
3.1 set注入和构造器注入
<beans>
<!-- 以构造方法注入 -->
<bean id="address" class="top.wmgx.spring.Address">
<constructor-arg name="name" value="asdfe"/>
</bean>
<!-- 注入 -->
<bean id="user" class="top.wmgx.spring.User">
<property name="name" value="lht"/>
<!-- 若为引用类型,用ref 称为bean注入-->
<property name="address" ref="address"/>
<property name="sex" value="男"/>
</bean>
3.2 其他注入
<bean id="user1" class="top.wmgx.spring.User">
<property name="grade">
<array>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
</array>
</property>
<!-- list注入-->
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<!-- map注入-->
<property name="map">
<map>
<entry key="a" value="12"/>
<entry key="b" value="12"/>
</map>
</property>
<!-- null值注入-->
<property name="address">
<null></null>
</property>
<!-- Properties-->
<property name="properties">
<props>
<prop key="jdbc">jdbc:mysql://loclhost:3306</prop>
<prop key="username">root</prop>
<prop key="pwd">pwd</prop>
</props>
</property>
3.3 p命名空间和c命名空间
3.3.1导入配置
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
3.3.2注入
<bean id="address" class="top.wmgx.spring.Address" p:name="address"/>
<bean id="address1" class="top.wmgx.spring.Address" c:name="address"/>
- p相当于是set注入
- c相当于是构造器注入
4 spring 配置
4.1 别名
<!--可以使用别名获取类-->
<alias name="user" alias="userNew"></alias>
<!--Bean中可以添加多个别名-->
<bean id="userT" class="top.wmgx.spring.UserT" name="user2,u2">
</bean>
4.2 导入其他配置文件
<import resource="beans.xml"/>
5. bean的作用域
-
代理模式(默认机制):get到的都是同一个对象。
<bean id="user2" class="top.wmgx.spring.User" c:age="18" c:name="AA" scope="singleton"/>
-
原型模式:每次从容器中get的时候,都会产生一个新的对象。
<bean id="user2" class="top.wmgx.spring.User" c:age="18" c:name="AA" scope="prototype"/>
-
equest、session、application 在web开发中使用。
6. Bean的自动装配
-
xml中显示配置
-
java中显示配置
-
隐式自动装配
6.1 byName自动装配
<!--
byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid!
-->
<bean id="address" class="top.wmgx.spring.Address" p:name="address"/>
<!--
user中的adddress 会自动注入上面的address
-->
<bean id="user" class="top.wmgx.spring.User" autowire="byName">
</bean>
注意:bean的ID需要和set方法后面的单词一致(首字母小写)
6.2 byType自动装配
<!--
byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid!
-->
<bean id="address" class="top.wmgx.spring.Address" p:name="address"/>
<!--
user中的adddress 会自动注入上面的address
-->
<bean id="user" class="top.wmgx.spring.User" autowire="byType">
</bean>
注意:bean中的class唯一,只能有一个这个类型的bean
7 注解自动装配
7.1 导入约束
加入
<!--
beans标签中加入 xmlns:context="http://www.springframework.org/schema/context"
与
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
同时开启注解配置支持
<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
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>
7.2 @Autowired
注解在属性上使用,可以不写set方法,
在使用@Autowired时,首先在容器中查询对应类型的bean
-
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据(byType)
-
如果查询的结果不止一个,那么@Autowired会根据名称来查找(byname)
-
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
7.3 @Resource
- @Resource默认按照名称方式进行bean匹配
- @Autowired默认按照类型方式进行bean匹配
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
二者既可以放在属性上也可以放在set方法上(set方法可以省略)
8 注解开发
8.1 导入aop包
在导入的 spring-webmvc:5.2.3中已经默认包含,使用低版本spring时要手动导入。
8.2 导入context约束
<!--指定要扫描的包,包下的注解会自动生效-->
<context:component-scan base-package="top.wmgx.spring"/>
8.3 注解
package top.wmgx.spring;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 声明是一个组件
//Component(“id”)可以指定ID 默认是首字母小写
@Component()
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
//相当于<property name="name" value="123123"/>
@Value("123123")
private String name;
}
8.3.1 自动装配
-
@Autowired:同上
-
@Resource:同上
-
@Value:值
-
@Qualifier(value="“bean的名字”")
- 一般不会单独使用,跟@Autowired 搭配使用。
- 即一个接口有多个实现类,在注入不同的实现类的时候,只用@Autowired就会出错,此时就要引入@Qualifier注释加以区分。
- value=“bean的名字”
-
@Nullable:字段标记了这个注解,说明这个字段可以为null
9 使用java配置Spring
9.1 编写配置类
package top.wmgx.spring;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
//表示会被spring接管
@Component
//表示这是一个配置类
@Configuration
//扫描哪个包
@ComponentScan("top.wmgx.spring")
//如果要引入其他的配置类
//可以使用 @Import(Config1.class)
public class Config {
//相当于是一个bean,方法名就是ID
@Bean
public User getUser(){
return new User();
}
}
9.2 测试类
package top.wmgx.spring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class UserTest {
@Test
public void Test(){
//注意改为了AnnotationConfigApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
User user =(User)context.getBean("getUser");
System.out.println(user);
}
}
10. AOP
10.1 什么是AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的频率。
10.2 使用
==提供声明式事务;允许用户自定义切面==
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志、安全、缓存、事务等等……
- 切面(ASPECT):横切关注点被模块化的特殊对象,即是一个类。
- 通知(Advice):切面必须要完成的工作,即是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知执行的“地点”的定义。
- 连接点(jointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
10.3 实现
10.3.1 导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
xml中要添加AOP的约束
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
10.3.2 通过 Spring API 实现
1. 编写业务接口和实现类
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
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("查询用户");
}
}
<?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"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<context:component-scan base-package="top.wmgx.spring"/>
<!-- 将切入类与要切入的类注册-->
<bean id="log" class="top.wmgx.spring.Log"/>
<bean id = "UserServiceImp" class="top.wmgx.spring.UserServiceImp"></bean>
<!-- 配置切入点-->
<aop:config>
<!-- 切入点的命名,要切入的方法-->
<!-- 1、execution(): 表达式主体。
2、第一个*号:表示返回类型, *号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
-->
<aop:pointcut id="pointcut" expression="execution(* top.wmgx.spring.UserServiceImp.* (..))"/>
<!-- 配置切入类,到具体的切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
Test
package top.wmgx.spring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void Test(){
ApplicationContext context = new ClassPathXmlApplicationContext("SpringTest.xml");
UserService user =(UserService)context.getBean("UserServiceImp");
user.add();
user.delete();
}
}
10.3.3 自定义类来实现Aop
写一个切入类
package top.wmgx.spring;
public class Log implements {
public void before() {
System.out.println("之前");
}
public void after() {
System.out.println("之后");
}
}
配置文件
<!-- 将切入类与要切入的类注册-->
<bean id="log" class="top.wmgx.spring.Log"/>
<bean id = "UserServiceImp" class="top.wmgx.spring.UserServiceImp"></bean>
<!-- 配置切入点-->
<aop:config>
<aop:aspect ref="log">
<aop:pointcut id="pointcut" expression="execution(* top.wmgx.spring.UserServiceImp.* (..))"/>
<!-- 配置切入类,到具体的切入点-->
<aop:before pointcut-ref="pointcut" method="before"/>
<aop:after pointcut-ref="pointcut" method="after"/>
</aop:aspect>
</aop:config>
10.3.4 注解实现
编写实现类
package top.wmgx.spring;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Log{
@Before("execution(* top.wmgx.spring.UserServiceImp.* (..))")
public void before() {
System.out.println("之前");
}
@After("execution(* top.wmgx.spring.UserServiceImp.* (..))")
public void after() {
System.out.println("之后");
}
@Around("execution(* top.wmgx.spring.UserServiceImp.* (..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();//手动调用执行
System.out.println("环绕后");
}
}
配置文件
<context:component-scan base-package="top.wmgx.spring"/>
<bean id="log" class="top.wmgx.spring.Log"/>
<bean id = "UserServiceImp" class="top.wmgx.spring.UserServiceImp"></bean>
<aop:aspectj-autoproxy/>
结果
11 Mybatis整合
11.1 导入相关jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>springtest</groupId>
<artifactId>springtest</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
<!-- annotations-java5-->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations-java5</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- aspectjweaver-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
实现方法一
不需要写 sqlSessionFactory 但是需要为原先的接口提供一个实现类,并且添加setSqlSession方法以接受setSqlSession ,并在接口是实现方法中提供setSqlSession的使用
-
配置数据源
<!--配置数据源:数据源有非常多,可以使用第三方的,也可使用Spring的--> <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
<!--配置SqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--关联Mybatis--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:top/wmgx/spring/dao/*.xml"/> </bean>
-
注册sqlSessionTemplate,关联sqlSessionFactory
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--利用构造器注入--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
-
增加Dao接口的实现类
public class UserDaoImp 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(); } }
-
配置mybatis的配置文件
<?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> <mappers> <mapper class="top.wmgx.spring.dao.UserDao"/> </mappers> </configuration>
-
注册Dao接口实现类
<bean id="userDao" class="top.wmgx.spring.dao.UserDaoImpl"> <property name="sqlSession" ref="sqlSession"/> </bean>
-
使用
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserMapper mapper = (UserMapper) context.getBean("userDao"); List<User> user = mapper.selectUser(); System.out.println(user); }
实现方法二
**mybatis-spring1.2.3版以上的才有这个 **
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate
-
UserDaoImp
public class UserDaoImp extends SqlSessionDaoSupport implements UserMapper { public List<User> selectUser() { UserMapper mapper = getSqlSession().getMapper(UserMapper.class); return mapper.selectUser(); } }
-
修改bean配置
<bean id="userDao" class="top.wmgx.spring.dao.UserDaoImp"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
-
测试
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserMapper mapper = (UserMapper) context.getBean("userDao"); List<User> user = mapper.selectUser(); System.out.println(user); }
12 事务
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理
事务管理器
- 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
- 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。
12.1 导入头文件约束
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
12.2 JDBC事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
12.3 配置事务的通知
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
12.4 配置AOP
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* top.wmgx.spring.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
12.5 事务的传播特性
spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。(默认)
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
以propagation_requierd举例
当一个方法中,连续调用多个方法,或间接调用多个方法,这些方法将会工作于一个事务中。