本文基于狂神说Java视频教程
狂神说java
优点
- 开源免费框架(容器)
- Spring是一个轻量级 非入侵式(引入Spring不会对原有项目产生任何影响)的框架
- 控制反转(IOC) 面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
组成
导入jar包
系统会自动将相关的jar包一起下载
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
核心配置文件 applicationContext.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">
</beans>
ioc的本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
HelloSpring
配置文件
<?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="mysqlImpl" class="com.kuang.dao.UserDaoMysqlImpl"/>
<bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl">
<!--ref是引用spring容器创建好的对象
value:具体的值 基本的数据类型
-->
<property name="userDao" ref="mysqlImpl"/>
</bean>
</beans>
测试类
public static void main(String[] args) {
//获取applicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("UserServiceImpl");
userServiceImpl.getUser();
}
ioc创建对象的方式
1使用无参构造创造对象 默认
2如果使用有参构造
<!--有参构造第一个方法下标--> <bean id="user" class="com.kuang.pojo.User"> <constructor-arg index="0" value="jack"/> </bean>
<!--第二种 通过类型创建 这种不建议使用--> <bean id="user" class="com.kuang.pojo.User"> <constructor-arg type="java.lang.String" value="javvv"/> </bean>
<!--第三种 直接通过参数名设置--> <bean id="user" class="com.kuang.pojo.User"> <constructor-arg name="name" value="jaaaaa"/> </bean>
在配置文件加载时,容器中的管理对象就已经初始化了
Spring的配置
- 别名
<!--别名 如果添加了别名可以用别名获取-->
<alias name="user" alias="usertoo"/>
id bean的唯一标识符 相当于我们学过的对象名
class bean对象所对应的类型 全限定名: 包名+类型
name也是别名 而且name可以同时取多个别名
依赖注入
- 构造器注入
- set方式注入(重点)
依赖注入
依赖:bean对象的创建依赖于容器
注入:bean对象的所有属性由容器注入
【环境搭建】
1.复杂类型
2.真实测试 - 扩展方式
.
bean的作用域
1spring默认单例模式
scope=“singleton”
2原型模式
每一次从容器中getBean的时候是一个新的对象
<bean id="user" class="com.kuang.pojo.User" p:age="1" p:name="aa" scope="prototype"/>
其余request,session,application 在web开发中使用
bean的自动装配
自动装配是Spring 满足bean依赖的一种方式
Spring会在上下文中自动寻找,并自动给bean装配
spring有三种装配模式
1 在xml中显示配置
2 在java中显示配置
3 隐式的自动装配bean(重要)
ByName自动装配
<!--ByName 会自动在容器的上下文中查找 和自己对象set方法后面值对应的beanid-->
<bean id="people" class="com.kuang.pojo.People" autowire="byName">
<property name="name" value="Jack"/>
</bean>
ByType
<!--ByType 会自动在容器的上下文中查找 和自己对象属性类型相同的beanid-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="Jack"/>
</bean>
小结
byname的时候保证所有bean的id唯一 这个bean需要和自动注入的属性的set方法的值一致。
byType的时候保证所有bean的class唯一 这个bean需要和自动注入的属性的类型一致。
使用注解实现自动装配
使用注解须知
1.导入约束 context约束
2.配置注解的支持 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>
@Autowired
直接在属性上使用即可
也可以在set方法上使用
可以不用编写set方法,前提是你这个自动装配的属性在IOC(Spring)中存在切符合Byname
@Autowired
private Cat cat;
@Autowired
private Dog dog;
科普
@Nullable 字段标记了这个注解 说明这字段可以为null
如果显示的定义了Autowired的required属性为false 说明这个对象可以为null 否则不能为空
如果自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候可以通过@Qualifier去配置@Autowired的使用
指定一个唯一的bean对象的注入
@Qualifier(value = “dog1”)
private Dog dog;
@Resource注解
public class People {
@Resource
private Cat cat;
@Resource
private Dog dog;
private String name;
小结 @Resource和@Autowired 的区别
都是用来自动装配都可以放在属性字段上
@Autowired通过bytype的方式实现 而且必须这个对象存在【常用】
@Resource默认通过byname 如果找不到名字,则通过bytype 如果都找不到则报错
执行顺序不同
使用注解开发
1.bean
2.属性如何注入
3.衍生的注解
4.自动装配
5.作用域
6.小结
@Component 组件放在类上 说明这个类被Spring 管理了
/*等价于<bean id="user" class="com.kuang.pojo.user*/
@Component
public class User {
public String name="waooo";
}
@Value(“jack”)//相当于
public String name;
@Component 有几个衍生注解 我们在web开发中会按照mvc三层架构分层
dao (@Repository)
service(@ervice)
controller(@Controller)
这四个注解的功能一样,都是代表将某个类注册到Spring中,装配Bean
xml更加万能 适用于任何场所
注解不是自己的类使用不了,维护复杂
xml和注解最佳实践。
xml只用来管理bean
注解只负责完成属性的注入
我们在使用过程中,如果使用注解,就必须开启注解的支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
<!--注解驱动-->
<context:annotation-config/>
使用Java的方式配置spring
现在不适用spring的xml配置 全权交给java
javaConfig
配置文件
package com.kuang.config;
import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author w
*///这个也会被spring容器托管,他本来就是一个组件(@Component)
//@Configuration代表这是一个配置类 就和我们之前看的beans.xml一样
@Configuration
@Import(MyConfig2.class)
public class MyConfig {
//注册一个bean 相当于我们之前写的bean标签
//这个方法的名字 相当于bean标签中的id属性
//返回值相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();//这就是要注入到bean的对象
}
}
实体类
package com.kuang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author w
*/
@Component//这个注解的意思就是说明这个类被spring接管 注册到容器中
public class User {
@Value("JACK")
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试
import com.kuang.config.MyConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author w
*/
public class MyTest {
public static void main(String[] args) {
//如果完全使用配置类 方式去做。我们就只能通过
//AnnotationConfig上下文来获取容器。通过配置了的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser.getName());
}
}
纯java的配置 在springboot中随处可见
10代理模式
代理模式是SpringAOP的底层
代理模式分为静态代理和动态代理
静态代理
角色分析
抽象角色:一般会使用接口或者抽象类来解决
真实角色:被代理的角色
代理角色:代理真实角色。代理真实角色后,我们会做一些操作
客户:访问代理对象的人
代理模式好处:
可以使真实角色的操作更加纯粹 不用关注公共的业务
公共也就交给代理角色 实现业务的分工
公共业务发生扩展的时候 方便集中管理
缺点
一个真实角色会产生一个代理角色,代码会翻倍 开发效率变低。
代码步骤
1:接口
package com.kuang.demo01;
/**
* @author w
*/
//租房
public interface Rent {
public void rent();
}
2:真实角色
package com.kuang.demo01;
/**
* @author w
*/
//房东
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
3:代理角色
package com.kuang.demo01;
/**
* @author w
*/
public class Proxy {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent(){
seeHouse();
hetong();
fare();
host.rent();
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
//合同
public void hetong(){
System.out.println("签订合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
4:客户端访问代理角色
package com.kuang.demo01;
/**
* @author w
*/
public class Client {
public static void main(String[] args) {
//房东要租房
Host host =new Host();
//代理 中介当房东租房,代理角色会有附属操作
Proxy proxy =new Proxy(host);
//你不用面对房东 直接找中介租房
proxy.rent();
}
}
代理模式加深理解
10.3动态代理
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
基于接口:jdk的动态代理【我们在这里使用】
基于类:cglib
java字节码的实现:javassist
需要了解两个类 Proxy 代理,InvocationHandler 调用处理程序的接口
InvocationHandler
11.AOP
在pom文件中导入相关包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一 使用spring的接口
方式二:使用自定义类
package com.kuang.diy;
/**
* @author w
*/
public class DiyPointCut {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("执行后");
}
}
<!--方法二 自定义类-->
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面 ref引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
方式三:使用注解
<!--方式三-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
package com.kuang.diy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* @author w
*/
//使用主角方式实现aop
@Aspect//标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
}
Spring整合mybatis
导入jar包
- junit
- mybatis
- mysql
- spring相关的
- aop织入
- mybatis-spring
<?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">
<parent>
<artifactId>spring-study</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-10-mybatis</artifactId>
<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.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring操作数据库的话 还需要一个spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
</project>
编写配置文件
测试
12.1回忆mybatis
- 编写实体类
- 编写核心配置文件
- 编写接口
- 编写mapper.xml
- 测试
12.2Mabits-spring
- 编写数据源
spring——daop
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--dataSource 使用spring的数据源替换mybatis c3p0 dbcp druid
这里使用spring提供的jdbc
-->
<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?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!--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:com/kuang/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory 因为他没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
<?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核心配置文件-->
<configuration>
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!--
<mappers>
<mapper class="com.kuang.mapper.UserMapper"/>
</mappers>-->
</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"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
</beans>
- sqlSessionFactory
- sqlSessionTemple
- 需要给接口加实现类
- 将自己的实现类 注入到spring中
- 测试
事务
事务的配置
在spring-dao.xml中
要加上
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--结合aop实现事务的织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给那些方法配置事务-->
<!-- 配置事务的传播特性 new propagation-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
事务为了解决数据提交不一致的情况
如果不配置 就需要在代码中配置