Spring
1、Spring
1.1简介:
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.2组成(七大模块)
1.3Hello Spring
步骤:
1、编写实体类
public class User {
private String name;
private int age;
}
2、编写application.xml文件(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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.hao.pojo.User">
<property name="name" value="hello Spring"/>
<property name="age" value="11"/>
</bean>
</beans>
3、测试
import com.hao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
User user = (User)context.getBean("user");
System.out.println(user.toString());
}
}
小结:将对象的创建(实例化)交给ioc容器管理,由ioc容器完成对象的属性注入
一句话就是对象由Spring来创建、管理、装配!
2、DI依赖注入
依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性,由ioc容器来注入
2.1构造器注入
前提:对象类中必须有有参构造方法
package com.hao.pojo;
public class User {
private String name;
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
<?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="user" class="com.hao.pojo.User">
<!--第三种,使用下标的方式给对象属性赋值-->
<constructor-arg index="0" value="hello Spring"/>
<!--第二种,根据对象属性的类型来给对象属性赋值-->
<constructor-arg type="java.lang.String" value="豪神"/>
<!--第一种,使用对象属性的名字给对象属性赋值-->
<constructor-arg name="name" value="123"/>
</bean>
</beans>
2.2set方法注入
前提:必须有无参构造方法,使用无参构造注入
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
<?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="user" class="com.hao.pojo.User">
<property name="name" value="hello Spring"/>
<property name="age" value="11"/>
</bean>
</beans>
2.3基于注解的注入
2.4c命名和p命名空间注入(扩展)
注意:需要导入c命名和p命名的头文件的约束
其实就是构造器注入和set注入方式一样,一个根据构造器注入属性值,一个直接set进去属性值。
3、Bean的作用域
- singleton:单例模式,在整个Spring IoC容器中,使用singleton 定义的 bean 只有一个实例(默认使用单例模式)
<bean id="user" class="com.hao.pojo.User" scope="singleton">
<property name="name" value="hello Spring"/>
<property name="age" value="11"/>
</bean>
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
User user = context.getBean("user",User.class);
User user2 = context.getBean("user",User.class);
System.out.println(user==user2);
}
}
//结果为true
- prototype:原型模式,每次通过容器的getBean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
<bean id="user" class="com.hao.pojo.User" scope="prototype">
<property name="name" value="hello Spring"/>
<property name="age" value="11"/>
</bean>
public class Mytest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
User user = context.getBean("user",User.class);
User user2 = context.getBean("user",User.class);
System.out.println(user==user2);
}
}
//结果为false
- 只有在 Web 应用中使用Spring时,request、session、global-session 作用域才有效
- request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
- session:同一个 Session 共享一个 bean 实例。
- global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。
4、Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式。
- Spring会在上下文中自动寻找,并自动给bean装配属性。
自动装配的方式:
- byName:根据bean的名字进行装配,当一个bean的名称和其他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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.hao.pojo.Cat"/>
<bean id="dog" class="com.hao.pojo.Dog"/>
<bean id="people" class="com.hao.pojo.People" autowire="byName">
<property name="name" value="锦豪"/>
</bean>
</beans>
- byType:根据bean的类型进行装配,当一个bean的属性类型与其他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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.hao.pojo.Cat"/>
<bean id="dog" class="com.hao.pojo.Dog"/>
<bean id="people" class="com.hao.pojo.People" autowire="byType">
<property name="name" value="锦豪"/>
</bean>
</beans>
还可以使用@Autowite、@Resource注解来实现自动装配
注意:使用注解需要在xml文件中导入context的注解支持
<context:annotation-config/>
小结:
- byName的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
- byType的时候,需要保证所有的class的唯一,并且这个bean需要和自动注入的属性的类型一致。
5、使用注解开发
-
@Component:组件,放在类上,说明这个类被Spring的IOC容器托管了,就是相当于一个bean。
-
@Scope:bean的作用域
-
@Value:给bean中的属性赋值。
-
衍生的注解:
- dao层 @Repository
- service层 @Service
- controller层 @Controller
6、AOP
6.1 什么是AOP?
切面编程,就是在你项目原有的功能基础上,通过AOP去添加新的功能,这些功能是建立在原有功能的基础上的,而且原有的功能并不知道你已经添加了新的功能。比如说,你去ATM取钱,取钱是一个功能,取完钱后向你的手机发送一条取钱信息,这就是新加的功能。
AOP就是在某一个类或方法执行前后打个标记,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么。插入了新的执行方法。
当我们需要在许多类中添加相同逻辑(或记录等其他)代码的时候,一般我们编程会在每一个类中都写上这些代码。当需要修改的时候,我们又必须找出这些类来删除这些逻辑代码。这里,你觉不觉得有什么问题。这好像关系到复用的问题,那么可以用聚合或继承来完成?那么再继续下去,我们需要这些逻辑代码指定到类中的某个方法前面执行,或者在方法后面执行,又或者我想指定在类的某一个位置去执行它,那么这就不是复用的问题了,而是要修改类了,变成动态的了。那么就出现了aop这个概念-面向切面编程。
如上图,黑线为一个流程代码,红线为切入的代码。即在5个流程中固定位置插入了3个逻辑代码,如果你不需要的时候,你完全可以撤出红线代码,而要修改的话,也只需修改这三个类(红线)即可,因为主代码(黑线)和添加代码(红线)是没有耦合的,相当于插拔式的。而且spring aop支持声明式的配置,使得aop更加方便。
6.2使用Spring实现Aop
注意:在使用Aop之前,需要导入aop的依赖包,还需要再xml配置文件中导入aop的约束
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
<?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">
</beans>
方式一:使用Spring的API接口来实现AOP【主要是SpringApi接口的实现】
实现Springaop的接口,生成执行环绕前后的类
package com.hao.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
//method: 要执行的目标对象的方法
// args: 参数
//target: 目标对象
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");
}
}
package com.hao.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"的方法,返回结果为"+returnValue);
}
}
编写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: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.hao.service.UserServiceImpl"/>
<bean id="before" class="com.hao.log.BeforeLog"/>
<bean id="after" class="com.hao.log.AfterLog"/>
<!-- aop的第一种方式-->
<aop:config>
<aop:pointcut id="pointCut" expression="execution(* com.hao.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="before" pointcut-ref="pointCut"/>
<aop:advisor advice-ref="after" pointcut-ref="pointCut"/>
</aop:config>
</beans>
方式二:自定义来实现AOP【主要是切面定义】
自定义一个切面
package com.hao.diy;
public class DiyPointCut {
public void before(){
System.out.println("==========方法执行前==========");
}
public void after(){
System.out.println("==========方法执行后==========");
}
}
编写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: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.hao.service.UserServiceImpl"/>
<!--第二种方法-->
<bean id="diy" class="com.hao.diy.DiyPointCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.hao.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
方式三:使用注解实现aop
其实就是将方式二使用注解的方式实现
定义一个切面类
package com.hao.diy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect //标注这个类为一个切面
public class AnnotationPointCut {
@Before("execution(* com.hao.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("==========方法执行前===========");
}
}
注意:在使用注解实现aop时,需要在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:aop="http://www.springframework.org/schema/aop"
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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userService" class="com.hao.service.UserServiceImpl"/>
<!--第三种aop实现方式-->
<context:component-scan base-package="com.hao"/>
<context:annotation-config/>
<aop:aspectj-autoproxy/>
</beans>
7、Spring整合Mybatis
步骤:导入jar包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
</dependencies>
2、编写mybatis-config.xml,Spring-dao.xml,和application.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.hao.pojo"/>
</typeAliases>
</configuration>
<?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="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=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件和映射mapper.xml文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/hao/mapper/*.xml"/>
</bean>
<!--就是我们平常使用的SqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--<constructor-arg index="0" ref="sqlSessionFactory"/>-->
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
<?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">
<import resource="spring-dao.xml"/>
<bean id="userMapper2" class="com.hao.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="userMapper" class="com.hao.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
3、编写实体类、接口、接口的实现类、mapper.xml文件
package com.hao.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String myname;
private int age;
private String address;
}
package com.hao.mapper;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> queryUser();
}
package com.hao.mapper;
import com.hao.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> queryUser() {
return sqlSession.getMapper(UserMapper.class).queryUser();
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.mapper.UserMapper">
<select id="queryUser" resultType="com.hao.pojo.User">
select * from users
</select>
</mapper>
4、测试
import com.hao.mapper.UserMapper;
import com.hao.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Mytest {
public static void main(String[] args) throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicaionContext.xml");
UserMapper mapper = context.getBean("userMapper", UserMapper.class);
for (User user : mapper.queryUser()) {
System.out.println(user);
}
}
}
8、Spring事务
- 声明式事务:AOP
再配置文件spring-dao.xml中配置事务,并横切进去
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<tx:advice id="TxAdvice" transaction-manager="transaction">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.hao.mapper.*.*(..))"/>
<aop:advisor advice-ref="TxAdvice" pointcut-ref="txPointCut"/>
</aop:config>
- 编程式事务:需要在代码中,进行事务的管理
为什么要使用事务?
- 如果不配置事务,可能存在数据提交不一致的情况
- 如果我们不在Spring中去配置事务,就需要在代码中手动配置事务
- 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎。