本文目录
- 搭建Spring环境
- Spring 配置多个文件加载
- Spring Ioc 实例化 Bean 对象的三种方式
- Spring DI 依赖注入 四种注入方式
- 面向切面编程 AOP
- Bean 的作用域
- Spring 整合JDBC
- Spring JDBC 事务
搭建Spring环境
1. 创建maven项目
2. 添加gra坐标,加入Spring框架的jar包pom文件中
3. 编写Spring的配置文件spring-config.xml
4. 创建待初始化bean对象,并在spring-config.xml配置文件中进行配置
5. 测试
Spring配置多个文件加载
有两种情况:
在Spring容器加载配置文件时加载多个配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("hello.xml","dao.xml");
在xml配置文件中,使用import标签将子配置文件导入到总的配置文件中
<import resource="dao.xml"/>
<!--(hello.xml中导入了dao.xml),此时,使用Spring框架加载配置文件时,只需要加载总的配置文件即可-->
Spring Ioc 实例化Bean对象的三种方式
空构造方式:
配置spring-config.xml,
<bean id="别名" class="完全限定名"></bean>
注意事项:
待初始化的bean必须要提供空参构造器
如果没有空参构造器就会报错
静态工厂模式:
特点:要有该工厂类(用来生成bean对象的),以及工厂方法,
工厂方法一定要是静态方法
配置:<bean id="待初始化类的别名" class="工厂类的class" factory-method="生产待初始化类的静态方法名"></bean>
示例
<bean id="goodsService" class="cn.edu.ncu.StaticFactory" factory-method="createGoodsService"></bean>
实例化工厂模式:
第一步,利用空参构造模式,将实例化工厂创建出来
<bean id="实例化工厂类的别名" class="实例化工厂类的完全限定名" ></bean>
第二步,再利用创建出来的实例化工厂来创建待初始化的bean
<bean id="bean的别名" factory-bean="实例化工厂类的别名" factory-method="实例化工厂类的非静态工厂方法"></bean>
示例
<bean id="instanceFactory" class="cn.edu.ncu.InstanceFactory" ></bean>
<bean id="orderService" factory-bean="instanceFactory" factory-method="createOrderService"></bean>
Spring DI 依赖注入 四种注入方式
Setter注入:
格式:
<bean id="待初始化属性类的别名" class="待初始化属性类的完全限定名"></bean>
<bean id="bean的别名" class="bean的完全限定名">
<property name="bean里面的属性名称" ref="待初始化属性类的别名"></property>
</bean>
示例:
<bean id="userDao" class="cn.edu.ncu.UserDao"></bean>
<bean id="userService" class="cn.edu.ncu.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
构造器注入:
第一步:必须提供带一个参构造器
第二步:进行配置
格式:
<bean id="属性的别名" class="完全限定名"></bean>
<bean id="bean的别名" class="完全限定名">
<constructor-arg index="0" ref="userDao001" ></constructor-arg>
<constructor-arg index="1" value="xaioqiang"></constructor-arg>
</bean>
示例:
<bean id="userDao001" class="cn.edu.ncu.UserDao"></bean>
<bean id="userService" class="cn.edu.ncu.UserService">
<constructor-arg index="0" ref="userDao001" ></constructor-arg>
<constructor-arg index="1" value="xaioqiang"></constructor-arg>
</bean>
构造器注入一共有3种形式:
(1)根据index索引来匹配的
(2)根据name属性名称来匹配的
(3)根据type类型进行匹配
问题:如果构造器中有多个类型相同的参数,将如何使用type类型进行依赖注入?
此时会按照***顺序***进行注入
(String a, String b, String c)
<constructor-arg type="String" value="userDao001" ></constructor-arg>
<constructor-arg type="String" value="xaioqiang"></constructor-arg>
<constructor-arg type="String" value="daqiang"></constructor-arg>
a = userDao001, b = xaioqiang, c = daqiang
静态工厂注入:
实质上是 Ioc的静态工厂模式和DI的Setter注入
将需要的属性对象利用静态工厂创建出来
配置:
第一步:利用Ioc中的静态工厂面膜是创建被引用的对象
(需要有一个被引用对象的静态工厂,且静态工厂中的方法一定要是静态的)
<bean id="被引用对象的别名" class="创建被引用对象的工厂" factory-method="该静态工厂中的静态方法"></bean>
<bean id="bean的别名" class="bean的class">
<property name="bean类中属性的名称" ref="被引用对象的别名"></property>
</bean>
实例化工厂注入:
实质上是Ioc的实例化工厂和DI的Setter注入
将需要的属性对象利用实例化工厂创建出来
Spring的Ioc(控制反转)和DI(依赖注入)的关系:相辅相成
Ioc:侧重于bean的创建 (有三种方式)
空构造模式、静态工厂模式、实例化工厂模式
DI:侧重bean的属性注入(有四种方式)
Setter注入、构造器注入、静态工厂注入、实例化化工厂注入
DI 产生的循环依赖问题
构造器注入时,必须先注入再创建对象,这样就会产生循环依赖问题
Setter注入,先创建对象再注入。恰好就是解决了构造器注入带来的循环依赖问题
DI注入List集合
<bean id="userService" class="cn.edu.ncu.UserService">
<property name="foodList">
<list>
<value>河南烩面</value>
<value>南方臊子面</value>
<value>油泼面</value>
<value>刀削面</value>
<value>安徽板面</value>
</list>
</property>
</bean>
DI注入Set集合
<bean id="userService" class="cn.edu.ncu.UserServcie">
<property name="foodSet">
<set>
<value>快乐小馒头</value>
<value>北方大馒头</value>
<value>东北大麻花</value>
</set>
</property>
</bean>
DI注入Map
<bean id="userService" class="cn.edu.ncu.UserServcie">
<property name="mapSence">
<map>
<entry>
<key><value>河南</value></key>
<value>云台山风景</value>
</entry>
<entry>
<key><value>北京</value></key>
<value>紫禁城</value>
</entry>
<entry>
<key><value>江西</value></key>
<value>庐山风景</value>
</entry>
</map>
</property>
</bean>
注解方式
配置命名空间和范围
xmlns:context="http://www.springframework.org/schema/context“
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
<!-- 添加注解的解析 -->
<context:annotation-config />
@Autowired和@Resource区别
相同点:都能够实现DI功能
不同点:
1、
@Autowired是spring提供的注解
@Resource是jdk提供的注解,并且spring框架也对@Resource提供了注解解析器
2、匹配模式
@Autowired默认按照bean的类型匹配
@Resource默认按名称进行装配。如果名称找不到,再按照类型匹配。名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行匹
配注入,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。
但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
推荐使用@Resource(jdk提供的)
import javax.annotation.Resource;
不推荐使用@Autowired(Spring提供的,会侵入代码)
import org.springframework.beans.factory.annotation.Autowired;
Spring Ioc 容器自动扫描管理 bean
Spring Ioc 容器自动扫描管理 bean
<context:component-scan base-package="cn.edu.ncu"/>
不需要再配置
<context:annotation-config/>
同时对于被spring管理的bean类的定义上需要加入对应的注解定义
开发中建议(开发中的一种约定)
Dao层:@Repository
Service层:@Service
视图控制层:@Controller
如果对于开发的类实在不明确到底属于哪个层,可以使用@Component注解定义。
面向切面编程 Aop
注解方式实现
配置命名空间和范围
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
配置Aop代理
<aop:aspectj-autoproxy/>
编写 aop 实现类
package cn.edu.ncu.aspectj;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Author ZhaiyiJun
* @Create by Masters on 2020-31-13-4:31.
* @Description: MAVEN
* @Modified by:[描述修改人]
* @Version: 1.0
* @History: [描述修改信息]
*/
@Aspect
@Component
public class LogCut {
/*
* 定义切点,匹配方法,定义规则
* 匹配规则表达式含义 拦截 cn.edu.ncu.service 包下 以及子包下 所有类的所有
* */
@Pointcut("execution (* cn.edu.ncu.service..*.*(..))")
public void cut(){
}
/*
* 声明前置通知 并将通知应用到定义的切入点上
* 目标泪方法执行前 执行该通知
* */
@Before(value = "cut()")
public void before(){
System.out.println("开始了");
}
/*
* 声明最终通知 并将通知应用到定义的切入点上
* 目标泪方法执行完毕 执行该通知
* */
@After(value = "cut()")
public void after(){
System.out.println("结束了");
}
/**
*声明最终通知 并将通知应用到切入点上
* 目标类方法执行过程中是否发生异常 均会执行该通知 相当于异常中的 finally
*/
@AfterReturning(value = "cut()")
public void afterReturning(){
System.out.println("Aop的返回通知");
}
/**
* 声明异常通知 并将通知应用到切入点上
* 目标类方法执行时发生异常 执行该通知
*/
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrow(Exception e){
System.out.println("Aop的异常抛出通知" + e);
}
}
XML 配置方式实现
<!-- aop 相关配置 -->
<aop:config>
<!-- aop 切面配置 -->
<aop:aspect ref="logCut">
<!-- 定义 aop 切入点 -->
<aop:pointcut expression="execution (* com.mage.service..*.*(..))" id="cut"/>
<!-- 配置前置通知 指定前置通知方法名 并引用切入点定义 -->
<aop:before method="before" pointcut-ref="cut"/>
<!-- 配置返回通知 指定返回通知方法名 并引用切入点定义 -->
<aop:after-returning method="afterReturning" pointcut-ref="cut"/>
<!-- 配置异常通知 指定异常通知方法名 并引用切入点定义 -->
<aop:after-throwing method="afterThrowing" throwing="e" pointcut ref="cut"/>
<!-- 配置最终通知 指定最终通知方法名 并引用切入点定义 -->
<aop:after method="after" pointcut-ref="cut"/>
<!-- 配置环绕通知 指定环绕通知方法名 并引用切入点定义 -->
<aop:around method="around" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
编写 aop 实现类
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
/**
*
* 声明切面组件
* */
@Component
public class LogCut {
public void before() {
System.out.println("前置通知.....");
}
public void afterReturning() {
System.out.println("返回通知....");
}
public void after() {
System.out.println("最终通知....");
}
public void afterThrowing(Exception e) {
System.out.println("异常通知....方法执行异常时执行:" + e);
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前置...");
System.out.println("环绕通知");
System.out.println(pjp.getTarget() + "--" + pjp.getSignature());
Object result = pjp.proceed();
System.out.println("环绕后置...");
return result;
}
}
Bean的作用域
Spring 作用域(scope 属性)
1、 singleton 作用域:
在框架启动时创建bean初始化放入缓存池中
scope的属性值默认是singleton 单例的
时间:在框架启动时创建bean
模式:单例模式,启动时将创建的bean放入到缓存池中
每次调用时,都是调用缓存池中的对象
2、lazy-init 懒加载:
时间:lazy-init="true", 框架启动时不初始化bean,
等到调用时再初始化bean,存在安全隐患
lazy-init="false"(bean标签中默认配置)
框架启动时就将bean初始化到单例缓存池中,程序启动时速度慢,但是调用bean时,不存在安全隐患
3、prototype 作用域
prototype 每次请求创建一个全新的bean并返回,不会缓存
时间:在bean 对象被调用的时候创建,不会被框架启动的时候被调用
模式:不是单例模式
Spring整合JDBC
配置坐标依赖
<!--mysql 驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- c3p0 连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
配置db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/user?serverTimezone=UTC
jdbc.user=root
jdbc.password=zyj18435790158@.
配置spring-config.xml
<context:component-scan base-package="cn.edu.ncu"/>
<!-- 加载 properties 配置文件 -->
<context:property-placeholder location="db.properties" />
<!--加载数据库配置文件-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--配置jdbc数据库的操作模板-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
编写模板类
package cn.edu.ncu.dao;
import cn.edu.ncu.model.Customer;
import cn.edu.ncu.util.StringUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@Repository
public class CustomerDao {
@Resource
private JdbcTemplate jdbcTemplate;
/**
* 实现带参查询封装结果
* @param name
* @return
*/
public Customer QueryCustomerByName(String name){
String sql = "select id, user_name, user_balance from yg_customer where user_name= ?";
return jdbcTemplate.queryForObject(sql, new Object[]{name}, new RowMapper<Customer>() {
@Override
public Customer mapRow(ResultSet resultSet, int i) throws SQLException {
Customer customer = new Customer();
customer.setId(resultSet.getInt(1));
customer.setUserName(resultSet.getString(2));
customer.setUserBalance(resultSet.getDouble(3));
return customer;
}
});
}
/**
* 实现多条件查询
* @param id
* @param name
* @return
*/
public List<Customer> queryCustomerByNameOrId(Integer id, String name){ // int 默认值是0,Integer 默认值是null
String sql = "select id, user_name, user_balance from yg_customer where 1 = 1";
//参数封装
List<Object> params = new ArrayList<Object>();
if(id != null){
sql += " and id = ?";
params.add(id);
}
if(!StringUtil.isBlankOrNull(name)){
sql += " and user_name = ?";
params.add(name);
}
List<Customer> customerList = jdbcTemplate.query(sql, params.toArray(), new RowMapper<Customer>() {
@Override
public Customer mapRow(ResultSet resultSet, int i) throws SQLException {
Customer customer = new Customer();
customer.setId(resultSet.getInt(1));
customer.setUserName(resultSet.getString(2));
customer.setUserBalance(resultSet.getDouble(3));
return customer;
}
});
return customerList;
}
}
package cn.edu.ncu.dao;
import cn.edu.ncu.model.Goods;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
@Repository
public class GoodsDao {
@Resource
private JdbcTemplate jdbcTemplate;
/**
* 添加商品,返回受到影响的行数
* @param goods
* @return
*/
public int addGoodsHasNoKey(Goods goods){
String sql = "INSERT INTO yg_goods(goods_name, goods_price, goods_stock) VALUES (?,?,?)";
int res = jdbcTemplate.update(sql,new Object[]{goods.getGoodsName(),
goods.getGoodsPrice(),
goods.getGoodsStock()});
return res;
}
/**
* 添加商品, 返回添加记录的主键
* @param goods
* @return
*/
public int addGoodsHasKey(final Goods goods){
final String sql = "INSERT INTO yg_goods(goods_name, goods_price, goods_stock) VALUES (?,?,?)";
// 定义 keyHolder 对象,获取记录的主键值
KeyHolder keyHolder = new GeneratedKeyHolder();
int res = jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
// 重新组装ps,预编译快
PreparedStatement preparedStatement= connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// 组装参数
preparedStatement.setString(1,goods.getGoodsName());
preparedStatement.setDouble(2,goods.getGoodsPrice());
preparedStatement.setInt(3,goods.getGoodsStock());
return preparedStatement;
}
}, keyHolder);
return keyHolder.getKey().intValue();
}
/**
* 更新商品库存
* @param id
* @param stock
* @return
*/
public int updateGoodsStockById(int id, int stock){
String sql = "UPDATE yg_goods set goods_stock = ? WHERE id = ?";
int res = jdbcTemplate.update(sql, new Object[]{stock, id});
return res;
}
/**
* 根据 id 删除商品
* @param id
* @return
*/
public int updateGoodsById(int id){
String sql = "delete from yg_goods where id = ?";
int res = jdbcTemplate.update(sql,new Object[]{id});
return res;
}
/**
* 根据 id 批量删除
* @param ids
* @return
*/
public int deleteGoodsBatch(final Integer[] ids){
String sql = "delete from yg_goods where id = ?";
return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
preparedStatement.setInt(1,ids[i]);
}
@Override
public int getBatchSize() {
return ids.length;
}
}).length;
}
/**
* 批量插入商品信息
* @param list
* @return
*/
public int addGoodsBatch(final List<Goods> list){
String sql = "INSERT INTO yg_goods(goods_name, goods_price, goods_stock) VALUES (?,?,?)";
return jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
// 重组参数
preparedStatement.setString(1, list.get(i).getGoodsName());
preparedStatement.setDouble(2,list.get(i).getGoodsPrice());
preparedStatement.setInt(3,list.get(i).getGoodsStock());
}
@Override
public int getBatchSize() {
return list.size();
}
}).length;
}
}
Spring JDBC 事务
配置命名空间和范围
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
配置spring-config.xml
<!--sping事务管理 配置注解支持-->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- spring 注解式事务声明 -->
<!-- 事务管理器定义 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>