Spring
Spring概要
**概述:**它是轻量级的开源的JavaEE框架
轻量级:它的体积小,依赖的jar包比较少,并且不需要额外依赖其他的组件
开源:免费提供源代码
框架:可以简化我们构建软件的过程
**目的:**为了解决企业级应用的复杂性
核心:
IOC:控制反转,把创建对象的过程交给Spring进行管理
AOP:面向切面编程–不修改源码进行功能增强
优点:
方便解耦,简化开发
对AOP编程的支持
方便程序的测试
方便整合其他各种的框架
方便进行事务开发
降低API成本
入门案例
IOC容器
概述:
控制反转
综上所述:控制反转就是把创建对象,和对象的调用过程交给Spring来管理。目的是为了降低类与类之间的耦合性
底层原理:
XML解析
工厂模式
反射
原理图解:
几个重要的概念:
1.IOC容器:IOC的实现,依赖于IOC容器,而IOC容器本质就是对象工厂
2.IOC容器的实现:
BeanFactory:是最底层的接口,它只提供了最简单的容器功能:加载配置文件和创建对象
当加载配置文件时,不会创建被配置的对象,只有在使用时,对象才会创建。
好处:节省内存
坏处:因为在服务器运行的时候去创建对象,会影响执行效率
ApplictionComtext :应用上下文,它是继承了BeanFactory。它是Spring更高级的一个容器接口,它提供了更多有用的功能
当加载配置文件的时候,会同时创建被配置的对象
好处:效率高,将复杂的创建过程在服务器启动时完成
坏处:耗费资源
-
ApplictionComtext的两个实现类:
ClassPathXmlApplicationContext:从项目中的resources文件中加载配置文件
FileSystemXmlApplicationContext:从文件系统读取配置文件(需要访问权限)
AnntationConfigApplicationContext:读取注解配置
IOC操作-Bean管理
**概念:**IOC操作—Bean管理是指两个操作:1.Spring创建对象2.Spring注入属性
实现方式:
1.XML方式
2.注解方式
基于XML方式-创建对象
该方式与入门案列方式相同
bean标签中的常用属性
id:唯一表示,通过该属性可以找到对应的Bean标签
class:类的全限定类名
注意事项:
创建对象是,默认执行无参构造来完成对象的创建(反射)
基于XML方式-注入属性
**DI:**依赖注入,它是IOC的一个具体操作
分类:
1.使用Set方法进行注入
2.使用构造器进行注入
演示:
属性注入通过
name:实体类属性名
value:属性值
构造方法注入
构造方法注入通过
P命名空间的注入
P命名空间的注入
xmlns:p="http://www.springframework.org/schema/p" 引入约束
<bean id="book" class="com.wdzl.pojo.Book" p:name="Java入门宝典" p:author="Tong"/>
特殊符号注入
1.null
<property name="name">
<null></null>
</property>
2.使用转译字符
3.CDATA
<property name="author">
<value><![CDATA[<Tong>]]></value>
</property>
外部bean
1.兴建Muole,在pom.xml中添加相关依赖
2.按照三层架构创建:Dao service web 在dao层中添加一个方法,在Service层中添加对Dao层的依赖(dao成员变量,对应的set方法)
3.配置对象信息
内部bean
1.在上一个演示案例的基础上,创建两个实体类Emp和Dept 其中Emp包含一个Dept对象属性
2.配置对象信息
级联操作
数组,集合属性的注入
基本数据类型:
1.创建一个实体类
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Demo {
private String[] strings;
private List<String> list;
private Map<String, String> map;
public Demo() {
}
public Demo(String[] strings, List<String> list, Map<String, String> map) {
this.strings = strings;
this.list = list;
this.map = map;
}
public String[] getStrings() {
return strings;
}
public void setStrings(String[] strings) {
this.strings = strings;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
@Override
public String toString() {
return "Demo{" +
"strings=" + Arrays.toString(strings) +
", list=" + list +
", map=" + map +
'}';
}
}
2.配置对象信息
<?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="demo" class="com.wdzl.pojo.Demo">
<!--字符串数组-->
<property name="strings">
<array>
<value>你好</value>
<value>Hello</value>
</array>
</property>
<!--list集合-->
<property name="list">
<list>
<value>Hello</value>
<value>Spring</value>
</list>
</property>
<!--map集合-->
<property name="map">
<map>
<entry key="hello" value="你好"></entry>
<entry key="Spring" value="春天"></entry>
</map>
</property>
引用数据类型:
1.创建实体类:城市类和省类
/**
* 城市类
*/
public class City {
private String cityName;
public City() {
}
public City(String cityName) {
this.cityName = cityName;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
@Override
public String toString() {
return "City{" +
"cityName='" + cityName + '\'' +
'}';
}
}
/**
* 省类
*/
public class Province {
private List<String> cities;
public Province() {
}
public Province(List<String> cities) {
this.cities = cities;
}
public List<String> getCities() {
return cities;
}
public void setCities(List<String> cities) {
this.cities = cities;
}
@Override
public String toString() {
return "Province{" +
"cities=" + cities +
'}';
}
}
2.配置对象信息
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- <bean id="province" class="com.wdzl.pojo.Province">
<property name="cities">
<list>
<ref bean="city1"></ref>
<ref bean="city2"></ref>
</list>
</property>
</bean>
<bean id="city1" class="com.wdzl.pojo.City">
<property name="cityName" value="西安"></property>
</bean>
<bean id="city2" class="com.wdzl.pojo.City">
<property name="cityName" value="长沙"></property>
</bean>-->
<util:list id="cityList">
<value>西安</value>
<value>长沙</value>
<value>北京</value>
</util:list>
<bean id="province" class="com.wdzl.pojo.Province">
<property name="cities" ref="cityList"></property>
</bean>
</beans>
FactoryBean:
**概述:**Spring中有两种类型的bean,一种是普通bean,一种是工厂bean
-
普通bean:在配置文件中定义的bean类型就是返回类型
-
工厂bean:在配置文件中配置bean类型与返回值类型不同
演示:
/**
* 工厂bean类型
*/
public class MyBean implements FactoryBean<String> {
/**
* 返回对象:此方法中定义了注入MyBean时,真正返回的对象
* @return
* @throws Exception
*/
@Override
public String getObject() throws Exception {
return "我是字符串";
}
/**
* 返回对象类型
* @return
*/
@Override
public Class<?> getObjectType() {
return null;
}
/**
* 是否是单例
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
<?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="myBean" class="com.wdzl.pojo.MyBean">
</bean>
</beans>
Bean的作用域
**概述:**在Spring中,设置创建Bean类型是单例还是多例。默认情况下,Bean实例是单例的
注意:
- Singleton 和 prototype的区别:
1.Singleton :在加载配置文件时,对象便会创建,并且,只创建一个对象
2.prototype:在加载配置文件时,并不创建对象,在调用getBean方法时,才会创建对象,并且每次调用都会创建
bean的生命周期
概述:
一个对象从创建到销毁的过程
过程:
- 通过构造器创建Bean实例
- 为Bean的属性设置值或引用其他Bean(调用set方法)
- 调用Bean的初始化方法
- Bean的对象获取
- 容器关闭,调用Bean的销毁方法
演示:
package com.wdzl.pojo;
/**
* 用户类
*/
public class User {
private String name;
public User() {
System.out.println("第一步:通过构造器创建对象");
}
public void setName(String name) {
System.out.println("第二步:为Bean的属性设置值");
this.name = name;
}
public void init() {
System.out.println("第三步:调用初始化方法");
}
public void destroy() {
System.out.println("第五步:调用销毁额方法");
}
}
import com.wdzl.pojo.User;
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("bean.xml");
User user = context.getBean("user", User.class);
System.out.println("第四步:获取对象");
( (ClassPathXmlApplicationContext)context).close();
}
}
<?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="user" class="com.wdzl.pojo.User" init-method="init" destroy-method="destroy">
<property name="name" value="唐康"></property>
</bean>
</beans>
-
在Bean的生命周期中,如果配置了后置处理,生命周期会额外的增加两步
过程:
- 通过构造器创建Bean实例
- 为Bean的属性设置值或引用其他Bean(调用set方法)
- 执行后置处理
- 调用Bean的初始化方法
- 执行后置处理
- Bean的对象获取
- 容器关闭,调用Bean的销毁方法
演示:
package com.wdzl.pojo;
/**
* 用户类
*/
public class User {
private String name;
public User() {
System.out.println("第一步:通过构造器创建对象");
}
public void setName(String name) {
System.out.println("第二步:为Bean的属性设置值");
this.name = name;
}
public void init() {
System.out.println("第四步:调用初始化方法");
}
public void destroy() {
System.out.println("第七步:调用销毁额方法");
}
}
import com.wdzl.pojo.User;
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("bean.xml");
User user = context.getBean("user", User.class);
System.out.println("第六步:获取对象");
( (ClassPathXmlApplicationContext)context).close();
}
}
<?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="user" class="com.wdzl.pojo.User" init-method="init" destroy-method="destroy">
<property name="name" value="唐康"></property>
</bean>
<bean id="myBeanLast" class="com.wdzl.pojo.MyBeanLast">
</bean>
</beans>
XML方式-自动装配
概述:
根据指定的装配规则(属性名称,属性类型),Spring自动将匹配的属性进行注入
实现:
借助标签里‘autowire’属性来实现自动装配,该属性有两个值:
- byName:根据属性名称注入
- byTYpe:根据属性类型注入
注意:
- byType:如果有多个class属性相同的bean标签,自动装配会报错
引入外部配置文件
<!--引入外部配置文件-->
<context:property-placeholder location="jdbc1.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${druid.driverClassName}"></property>
<property name="url" value="${druid.url}"></property>
<property name="username" value="${druid.username}"></property>
<property name="password" value="${druid.password}"></property>
</bean>
基于注解方式–创建对象
**注解概述:**注解是代码的特殊标记
注解格式:@注解名称 (属性名=属性值,属性名2=属性值…)
**注解应用:**它可以简化XML的配置,注解可以用在类上,属性上,方法上
Spring针对注解创建对象提供了4个注解:
-
@Component:普通类使用
-
@Service:Service层使用
-
Controller:web层使用
-
@Repository:Dao层使用
这四个注解功能是相同的,都可以用来创建Bean实例
步骤:
-
新建Moudule,添加依赖
-
创建UserDao,在该类上添加注解
package com.wdzl.dao; import org.springframework.stereotype.Repository; /** * */ @Repository(value = "userDao")//相当与id属性 public class UserDao { public void addUser() { System.out.println("UserDao:addUser...."); } }
3.在配置文件中开启组件扫描
<?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:component-scan base-package="com.wdzl.dao"></context:component-scan>
</beans>
4.测试
import com.wdzl.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DemoTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserDao userDao = context.getBean("userDao", UserDao.class);
System.out.println(userDao);
}
}
基于注解方式–属性注入
- @AutoWired:根据属性类型进行自动装载
- @Qualifier:根据属性名进行注入
- @Resource:根据类型注入,也可以根据名称注入
- @Value:基本数据类型的注入
演示:
@AutoWired:
@Qualifier:
- 要与@AutoWired同时使用
- 同时使用的目的是为了解决根据属性类型无法自动装载的情况:比如BookDao有多个实现类
@Resource:
JDBCTemplate
概述:
Spring对JDBC的封装,使用它可以方便的去操作数据库
依赖:
事务
事务环境搭建
-
新建一个Moudule,添加相关依赖
-
缩写配置wenjian
-
配置JdbcTemplate
- 注入数据源
-
开启组件扫描
-
-
缩写Dao层接口,service层接口,及相应的实现类
-
测试
事务操作
- 事务应该添加到三层架构中的service层
- 因为Service负责组装业务
2.在Spring中进行事务管理
编程式事务
声明式事务
3.声明式事务管理
基于注解方式
基于XML方式
4.在Spring中进行声明式事务管理使用AOP原理
5.Spring针对不同的框架使用不同的API
基于注解方式的事务管理
@Transactional常见属性:
- propagation :事务传播行为
- isolation: 事务隔离级别
- timeout:超时时间
- readOnly:是否只读
- rollbackFor:回滚
- noRollbackFor:不回滚
1.创建实体类
package com.wdzl.pojo;
/**
* 账户类
*/
public class Account {
private int id ;
private String name;
private double money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
2.数据库连接配置类
package com.wdzl.jdbc;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
/**
* 数据库连接配置类
*/
public class JdbcConfig {
@Bean//将DataSource注入Spring中
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("wangbiwu0412....");
return dataSource;
}
@Bean//将SqlSessionFactory注入到Spring容器中
public SqlSessionFactoryBean create(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
Resource resource = new ClassPathResource("SqlMapConfig");
sqlSessionFactory.setConfigLocation(resource);
return sqlSessionFactory;
}
}
3.配置类
/**
* 配置类
*/
@Configuration//配置类
@ComponentScan(basePackages = "com.wdzl")//组件扫描
@Import(value = {JdbcConfig.class, TransactionConfig.class})//引入其他配置类
@EnableTransactionManagement//开启事务
public class SpringConfig {
}
4.事务管理类
public class TransactionConfig {
@Bean
public PlatformTransactionManager createTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
5.dao层实现类
public interface AccountDao {
/**
* 根据用户名查询账户信息
* @param name
* @return
*/
@Select("select * from account where name=#{name}")
Account findAccountByName(String name) ;
/**
* 跟踪账户信息
* @param account
*/
@Update("update account set name=#{name},money=#{money} where id=#{id}")
void updateAccount(Account account);
}
/**
* 账户接口实现类
*/
@Repository
public class AccountDaoImpl implements AccountDao {
//注入sqlSession工厂
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public Account findAccountByName(String name) {
SqlSession sqlSession = sqlSessionFactory.openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
return accountDao.findAccountByName(name);
}
@Override
public void updateAccount(Account account) {
SqlSession sqlSession = sqlSessionFactory.openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
accountDao.updateAccount(account);
}
}
6.service层及其实现类
public interface AccountService {
/**
*转账业务
*/
void transfer(String sourceName, String targetName, double money);
}
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
public void transfer(String sourceName, String targetName, double money) {
//查询转出账户对象
Account source = accountDao.findAccountByName(sourceName);
//查询注入账户对象
Account target = accountDao.findAccountByName(targetName);
//判断账户是否存在
if (source !=null && target != null) {
//设置转出转入金额
source.setMoney(source.getMoney() - money);
target.setMoney(target.getMoney() + money);
//更新账户信息
accountDao.updateAccount(source);
//System.out.println(1/0);
accountDao.updateAccount(target);
}
}
}
7.账户控制层
@Controller
public class AccountController {
@Autowired
private AccountService accountService;
public void transfer(String sourceName, String targetName, double money) {
try {
accountService.transfer(sourceName, targetName, money);
System.out.println("转账成功");
} catch (Exception e) {
System.out.println("转账失败");
}
}
}
8.编写配置类
<?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="com.wdzl.dao.AccountDao"></mapper>
</mappers>
</configuration>
9.测试
public class AccountTest {
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountController accountController = context.getBean("accountController", AccountController.class);
accountController.transfer("bobo", "tong",500);
accountController.transfer("王必武","唐康",500.00);
}
}