目录
2.@Scope(Value="prototype") |"signleton"
3.@Autowired可以给属性自动注入值 默认值不能为空 如果允许null值,可以设置它的required属性为false
一.Spring概述
Spring 是于 2003 年兴起的一个轻量级的,IOC 和 AOP 的 Java 开发框架,它 是为了简化企业级应用开发而生的。
轻量级:Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核 心功能的所需的 jar 总共在 3M 左右。 Spring 框架运行占用的资源少,运行 效率高。
IOC: Inversion of Contraol , 在以前需要我们自己创建对象, 现在由Spring 里的 Ioc容器来管理对象, 需要时直接从框架获取即可.IOC是具有依赖注入功能的容器, 负责对象实例化, 对对象之间的依赖关系配置,功能的增强, 对象的销毁,对象的调用 都是由Spring框架实现
Aop面向切面编程:
Aop与oop的区别: oop是面向对象编程,是对整个程序全局的一种架构设计(战略层面),aop是oop的补充,是一种战术层面的.
Aop的大至作用:aop是将程序中的非业务代码进行抽取,将非业务代码与业务代码相隔离,耦合度降低,然后通过一个代理对象在业务代码中调取非业务代码,提高代码的灵活性.
Aop核心思想:使用一个代理对象,在中间帮忙调取,为我们的程序添加功能.注意aop思想不是spring特有的,是java中的一中代理思想.
一站式框架:spring核心是统一管理程序里的对象(IOC), 提供AOP思想, 话对数据访问层和web层进行封装, 还可以方便集成其他框架与组件, 一条龙服务.
二.Spring体系结构
三.Spring搭建
Maven导入核心的jar
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
编写spring配置文件
<?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.ffyc.springpro.model.User"> </bean>
</beans>
编写一个User实体类
public class User {
private Integer id;
private String name;
public User() {
System.out.println("user无参");
}
public User(Integer id, String name) {
System.out.println("user有参");
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
测试spring
public class Test1 {
@Test
public void springTest(){
ApplicationContext applicationContext
=newClassPathXmlApplicationContext("spring.xml");
User user1 = applicationContext.getBean("user1",User.class);
System.out.println(user1);
}
}
四.Spring Bean管理
1.基于xml配置方式
bean 配置需要 spring 管理的类
id 生成的对象名
name 也是生成的对象名
class 类的地址
scope:bean对象的作用域
singleton 在Spring只会出现一个bean 单例模式
prototype 每次getBean时都会出现一个新的bean对象
<bean id="user1" name="user2" class="com.ffyc.springpro.model.User" scope="prototype">-->
<property name="id" value="111"></property>
<property name="name" value="jim"></property>
</bean>
依赖注入(Dependency Injection)
在spring为我们创建对象时,需要为对象中的属性或者关联对象进行赋值操作(依赖注入)
依赖注入与控制反转是伴随发生的.
注入的方式:
set方式注入
构造方法注入
set方式注入
<bean id="UserDao" class="com.ffyc.springpro.dao.UserDao"></bean>
<bean id="UserService" class="com.ffyc.springpro.service.UserService">
<property name="userDao" ref="UserDao"></property> //ref是引用,该属性是引用类型
</bean>
构造方法注入
<bean id="user1" name="user2" class="com.ffyc.springpro.model.User" scope="prototype">
<constructor-arg name="id" value="111"></constructor-arg>
<constructor-arg name="name" value="jim"></constructor-arg>
</bean>
<bean id="UserDao" class="com.ffyc.springpro.dao.UserDao"></bean>
2.注解方式实现
导入注解需用的jar包
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
注解功能封装在aop包中,导入Spring aop jar 包即可
开启注解扫描,在xml文件中配置
<context:component-scan base-package="包名"> </context:component-scan>
注解
1.注解创造对象(@Component) 类似于<bean>标签的功能
但是为了区分各个功能
Service层使用@Service标签
Dao层使用@Repository
Pojo层使用@Ccomponent
@Component(value=“user”)等于<bean id="user" class= ></bean>
例如:
2.@Scope(Value="prototype") |"signleton"
单例模式或者原型模式 类似于<bean scope="">属性
3.@Autowired可以给属性自动注入值 默认值不能为空 如果允许null值,可以设置它的required属性为false
@Autowired可以写在属性上方(就不用写set方法了), 也可以写在set方法上
byType自动注入:默认通过类型来赵对应的Bean
byName自动注入:结合@Qualifier(value="名字")通过名字来找
@Resource功能和@Autowired一样 他是jdk里面的注解
注意:@Resource默认使用按名称自动装配;也可以按类型来装配
注解与xml的对比:
注解的优点: 方便,直观,高效(代码少,没有配置文件的书写那么复杂)
注解的缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的
xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重 启服务器即可将新的配置加载
xml 的缺点是:编写麻烦,效率低,大型项目过于复杂
3.Spring JDBC
Spring 是个一站式框架:Spring 自身也提供了控制层的 SpringMVC 和 持久 层的 Spring JdbcTemplate。
JDBC搭建
1.下载载 Spring JdbcTemplate的 jar 包
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
创建一个xml文件导入属性文件(推荐里面只写数据库配置)
<context:property-placeholder location="config.properties"/>
管理数据源对象
spring管理与数据库链接(数据源)
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${uname}"></property>
<property name="password" value="${upassword}"></property>
<property name="initialSize" value="10"></property>
<property name="minIdle" value="5"></property>
<property name="maxActive" value="20"></property>
</bean>
在配置文件中创建JdbcTemplate
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
在类中获得JdbcTemplate对象,就可以直接使用了
如下:可以直接在Dao层写sql语句
@Autowired
JdbcTemplate jdbcTemplate;
public void selectUser(User user){
List<User> list = jdbcTemplate .query("select * from admin where id>?", new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user1 = new User();
user1.setId(resultSet.getInt("id"));
user1.setName(resultSet.getString("account"));
return user1;
}
}, 0);
System.out.println("保存成功");
System.out.println(list.size());
}
JdbcTemplate 中常用的方法
execute:无返回值,可执行 ddl,增删改语句
update:执行新增、修改、删除语句
queryForXXX:执行查询相关语句
4.Aop概述
Aop意为面向切面编程,主要作用就是将我们日常写业务时,将那些非业务代码抽离出来,写成一个公共方法,提高程序的可重用性,提高了开发的效率,使得各部分之间的耦合度降低.
面向切面编程的好处就是: 减少重复,专注业务;
注意:面向切面编程只是面向对象编程的一种补充。
核心原理: 使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
使用案例:
事务处理:开启事务,关闭事务,出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理
Pointcut:切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。
Advice:处理,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。
Aspect:切面,即Pointcut和Advice。
Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。
Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。
springAop实现
AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实 现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,Spring 又 将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。
下载AOP相关的jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
基于aspectj的xml配置方式实现
<bean id="commenutil1" class="com.ffyc.springpro.util.Commenutil_back"></bean>
<aop:config>
<aop:pointcut id="inserAdmin" expression="execution(* com.ffyc.springpro.dao.*.*(..))"/>
<aop:aspect ref="commenutil1">
<!-- 前置通知,在方法执行之前被调用-->
<!-- <aop:before method="saveLog" pointcut-ref="inserAdmin"></aop:before>-->
<!-- 最终通知,无论方法是否正常运行,都会被调用-->
<!-- <aop:after method="saveLog" pointcut-ref="inserAdmin"></aop:after>-->
<!--后置通知,在方法正常执行之后被调用-->
<!-- <aop:after-returning method="saveLog" pointcut-ref="inserAdmin"></aop:after-returning>-->
<!--异常通知,当方法出现异常时,才会被调用 -->
<!-- <aop:after-throwing method="saveLog" pointcut-ref="inserAdmin"></aop:after-throwing>-->
<!--环绕通知,更加强大,更灵活 -->
<aop:around method="saveLog" pointcut-ref="inserAdmin"></aop:around>
</aop:aspect>
</aop:config>
aop:around实现
public void saveLog(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("前置通知");
try {
Object[] objects = proceedingJoinPoint.getArgs();
String s1 = Arrays.toString(objects);
System.out.println(s1);
proceedingJoinPoint.proceed();
System.out.println("后置通知");
}catch (Throwable t){
System.out.println(t.getMessage());
System.out.println("异常通知");
}
System.out.println("最终通知");
}
AspectJ 中常用的通知有五种类型: 前置通知,后置通知,环绕通知,异常通知,最终通知.
基于注解的方式实现
启动Aspectj支持:<aop:aspectj-autoproxy/>
定义通知
@Before("execution(* com.ffyc.springpro.dao.*.*(..))") 前置通知
@After("execution(* com.ffyc.springpro.dao.*.*(..))") 最终通知
@AfterReturning("execution(* com.ffyc.springpro.dao.*.*(..))") //后置通知
@AfterThrowing(value = "execution(* com.ffyc.springpro.dao.*.*(..))",throwing ="e" ) 异常通知
public void saveLog(JoinPoint joinPoint,Throwable e){
Object[] objects =joinPoint.getArgs();
String a= Arrays.toString(objects);
System.out.println(a);
System.out.println("保存时间:"+new Date()+"保存管理员:" +e.getMessage());
}
Around
@Around("execution(* com.ffyc.springpro.dao.AdminDao.*(..))")
public void saveLog(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("前置通知");
try {
Object[] objects = proceedingJoinPoint.getArgs();
String s1 = Arrays.toString(objects);
System.out.println(s1);
proceedingJoinPoint.proceed();
System.out.println("后置通知");
}catch (Throwable t){
System.out.println(t.getMessage());
System.out.println("异常通知");
}
System.out.println("最终通知");
}
5.Spring事务管理
事务的概念:事务时逻辑上的一组操作,要么都执行,要么不执行,是一个最小的不可再分的工作单元,通常一个事务对应一个完整的业务(例如银行转账业务,该业务就是最小的工作单元).
事务管理:是对于一系列数据库操作进行管理,一个事务包含一个或多个sql语句,是逻辑管理的工作单元,其实事务管理,就是按照给定的事务规则来执行提交或者回滚操作.
spring中的事务管理:
1.编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,就是必须在每个事务操作中包含额外的事务管理代码
2.声明式事务管理:它将事务管理代码从业务代码中分离出来,以声明的方式来实现业务管理
声明式事务管理有两种方式(推荐第二种):
1.使用xml配置
2.使用注解标签
Spring 针对不同的 dao 框架,提供了不同的实现类,Jdbc,mybatis 事物管理实 现类是 DataSourceTransactionManager.
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
开启注解事务管理
<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
在 service 中控制事务
@Service(value="userservice")
@Transactional
@Service(value = "adminService")
@Transactional
public class AdminService {
@Autowired
AdminDao adminDao;
// public void saveAdmin(Admin admin){
adminDao.inserAdmin(111,000);
// }
public void updateMoeny(){
adminDao.aidMnoey();
adminDao.addMoney();
}
}
声明式事务不生效的场景
@Transactional
应用在非 public 修饰的方法上
异常被 catch 捕获导致失效
默认情况下出现编译期异常是会失效,设置@Transactional(rollbackFor = Exception.class)
@Transactional 事务传播行为设置错误
数据库引擎不支持事务
同一个类中,使用非代理对象调用一个有事务的方法,导致事务错误.
6.Spring事务传播行为
事务传播行为概念:指的是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。事务传播行为时spring框架独有的事务增强特性,不属于事务提供方数据库行为.
例如:A的事务方法调用B的事务方法时,B是继续调用A的事务运行呢,还是开启一个新的事务运行,这就是由B的事务传播行为决定的.
Spring定义了七种传播行为(propagation:n.传播,宣传,培养):
1.REQUIRED:如果当前存在事务,则加入该事务,否则新建一个事务。这是最常见的传播行为,也是默认的传播行为。
2.SUPPORTS:支持当前事务,如果当前不存在事务,则以非事务方式执行。
3.MANDATORY:强制要求当前存在事务,如果不存在事务,则抛出异常。(mandatory:adj.强制的)
4.REQUIRES_NEW:重新开启一个新的事务,如果当前存在事务,则挂起该事务。(注意:默认的事务隔离级别——可重复读中 ,开启的新事务读不到之前挂起事务的操作,而且如果操作相同的表会导致锁表,一定要谨慎使用!)
5.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则挂起该事务。
6.NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
7.NESTED:如果当前存在事务,则嵌套事务中执行。嵌套事务是相对于外部事务而言的,它可以独立提交或回滚,但是嵌套事务的提交或回滚并不会对外部事务产生影响。如果外部事务不存在,那么 NESTED 与 REQUIRED 的效果是一样的。该传播行为只有在使用 JDBC 事务时才有效。
//@Transactional(propagation = Propagation.REQUIRED)
//A方法中没有事务,调用B方法,B方法会自己创建一个事务,在事务中运行,B方法出现异常,不影响A方法
//A方法有事务,调用B方法,B方法会自己加入到A的方法的事务中,两个合二为一,任意一方出现问题,都会影响双方
// @Transactional(propagation = Propagation.REQUIRES_NEW)
//A方法中没有事务,调用B方法,B方法会自己创建一个事务,在事务中运行,B方法出现异常,不影响A方法
//A方法有事务,调用B方法,B方法会自己创建一个事务,将A方法事务挂起,A方法出现异常,不会影响B事务