spring是于2003年兴起的一款轻量级的,非侵入式的IOC和AOP的一站式的java开发框架,为简化企业级应用开发而生
轻量级的:指的是spring核心功能的jar包不大。
非侵入式的:业务代码不需要继承或实现spring中任何的类或接口
IOC:控制反转(Inverse of Control),以前项目都是在哪儿用到对象,在哪儿new,把生成对象的权利反转给spring框架(让spring把对象管理起来,在哪用在哪注入)
AOP:面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
一站式框架:
1.Maven 导入 spring 核心基础 jar
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.2.RELEASEversion>
dependency>
2.编写一个Admin实体类
package com.ffyc.ssm.model;
public class Admin {
private Integer id;
private String account;
public Admin() {
System.out.println("admin无参构造");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
}
3.编写 spring 配置文件,在resources/spring.xml中
<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="admin" class="com.ffyc.ssm.model.Admin">bean>
beans>
4.测试spring
读取spring配置文件,并对文件中配置的对象进行创建
package com.ffyc.ssm.test;
public class Test1 {
public static void main(String[] args) {
/*以前使用对象方式,在哪儿用,在哪儿new
new Admin();
spring思想是,由框架统一对项目中的类进行管理(创建对象,后期增强一些功能),在需要的地方注入即可*/
//Map(admin,new Admin)
//ClassPathXmlApplicationContext就是spring中的实际实现者
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
//Object admin=app.getBean("admin");//不知道返回的类型,从Map中拿出new Admin对象
Admin admin=app.getBean("admin",Admin.class);//明确类型
System.out.println(admin);
}
}
正控:若要使用某个对象,需要自己去负责对象的创建
反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了 Spring 框架
**底层实现方式:**解析 xml/扫描注解标签 + 工厂模式 + 反射机制
配置需要让spring进行管理的类
id=“唯一的标识”
class=“让spring管理的类名”
bean对象?由spring框架创建并管理的对象
<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="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">bean>
beans>
public class Test1 {
public static void main(String[] args) {
//读取spring配置文件,并对文件中配置的对象进行创建
//ClassPathXmlApplicationContext就是spring中的实际实现者
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
Admin admin1=app.getBean("admin",Admin.class);
System.out.println(admin);
System.out.println(admin1);
}
}
/*
admin无参构造
admin无参构造
com.ffyc.ssm.model.Admin@685cb137
com.ffyc.ssm.model.Admin@6a41eaa2
*/
spring框架创建对象(控制反转)时,为对象的属性进行赋值操作(这个赋值操作称为依赖注入)
1.属性赋值 getXXX、setXXX方法
<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
<property name="id" value="10">property>
<property name="account" value="张三">property>
bean>
public class Test1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
System.out.println(admin);
}
}
/*
admin无参构造
Admin{id=10, account='张三'}
*/
2.构造方法赋值
<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
<constructor-arg name="id" value="1">constructor-arg>
<constructor-arg name="account" value="1">constructor-arg>
bean>
public class Test1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
System.out.println(admin);
}
}
//Admin{id=1, account='1'}
在一个方法中注入另一个方法
<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
<constructor-arg name="id" value="1">constructor-arg>
<constructor-arg name="account" value="1">constructor-arg>
bean>
<bean id="adminDao" class="com.ffyc.ssm.dao.AdminDao">bean>
<bean id="adminService" class="com.ffyc.ssm.service.AdminService">
<property name="adminDao" ref="adminDao">property>
bean>
public class Test2 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
AdminService adminService=app.getBean("adminService",AdminService.class);
adminService.save(admin);
}
}
1、注解需要的jar包
注解功能封装在AOP包中,导入 Spring aop jar 包即可
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.2.RELEASEversion>
dependency>
2、开启注解扫描
<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
https://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.ffyc.ssm"> context:component-scan>
beans>
3、注解创建对象
有注解标签才是spring管理的对象,并创建对象
1.@Component(value = “admin”) 一般用于模型类,等同于
2.@Scope(value=“prototype”) 原型(多次)
@Scope(value=“singleton”) 单例(一次)
@Component(value = "admin")
@Scope(value = "singleton")
3.@Repository(value = “adminDao”),用于dao层
@Repository(value = "adminDao")
public class AdminDao {
public void saveAdmin(Admin admin){
System.out.println("保存管理员"+admin);
}
}
4.@Service(value = “adminService”)
5.@Autowired,spring框架提供的一种自动注入的注解标签,可以写在字段和 setter 方法上。如果写在字段上,那么就不需要再写 setter 方法。默认情况下它要求依赖对象必须存在,如果允许 null 值,可以设置它的 required 属性为 false。
有两种方式去查找对象:
@Service(value = "adminService")
public class AdminService {
/*@Autowired
@Qualifier(value = "adminDao")
AdminDao adminDao;//依赖注入*/
//@Resource
@Resource(name = "adminDao")
AdminDao adminDao;
public void save(Admin admin){
adminDao.saveAdmin(admin);
}
}
public class Test3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
AdminService adminService=app.getBean("adminService",AdminService.class);
adminService.save(admin);
}
}
注解优点: 方便、直观、高效(代码少,没有配置文件的书写那么复杂)。
**注解缺点:**以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的(通过maven把项目重新编译compile一下)。
xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
**xml 缺点是:**编写麻烦,效率低,大型项目过于复杂
spring框架中的JDBC功能
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.2.RELEASEversion>
dependency>
导入mysql
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
导入阿里巴巴提供的数据源管理组件,数据源组件封装了连接数据库,还有数据库连接池功能
druid(德鲁伊),常用的数据库链接池组件:dbcp、c3p0
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.10version>
dependency>
2.config.properties
classDriverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai
uname=root
pwd=123456
3.db.xml
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:config.properties">context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${classDriverName}">property>
<property name="url" value="${url}">property>
<property name="username" value="${uname}">property>
<property name="password" value="${pwd}">property>
<property name="initialSize" value="5">property>
<property name="maxActive" value="10">property>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
beans>
4.spring.xml注解db.xml
<import resource="classpath:db.xml">import>
增删改用update
@Repository(value = "adminDao")
public class AdminDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void saveAdmin(Admin admin){
//jdbcTemplate.update("insert into admin(account,password)value(?,?)","aaa","111");
jdbcTemplate.update("delete from admin where id =?","5");
}
}
查询,返回单个结果
public void saveAdmin(Admin admin){
Admin admin2=jdbcTemplate.queryForObject("select * from admin where id=?",
new RowMapper<Admin>() {
@Override
public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
Admin admin1=new Admin();
admin1.setId(resultSet.getInt("id"));
admin1.setAccount(resultSet.getString("account"));
return admin1;
}
},1);
System.out.println(admin2);
}
查询,返回多个结果
public void saveAdmin(Admin admin){
List<Admin> adminList=jdbcTemplate.query("select * from admin",
new RowMapper<Admin>() {
@Override
public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
Admin admin1=new Admin();
admin1.setId(resultSet.getInt("id"));
admin1.setAccount(resultSet.getString("account"));
return admin1;
}
});
System.out.println(adminList);
}
案例:
先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要写两个非业务方法。非业务方法也称为交叉业务逻辑:
AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,AOP 可以**对业务逻辑和非业务逻辑进行隔离,从而使得各部分之间的耦合度降低,提高程序的可重用性,**同时提高了开发的效率。将程序中的一些非业务代码进行提取,在不需要修改原来代码的情况下,为程序添加额外的功能。
AOP思想不是spring框架特有的,只是spring框架引入使用了这一思想。
面向切面编程的好处就是: 减少重复,专注业务;
注意:面向切面编程只是面向对象编程的一种补充。
核心原理: 使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
非业务代码使用案例:
**连接点(Joinpoint):**类中可以被增强的方法
**切入点(pointcut):**类中有很多方法可以被增强,但实际中只有 add 和 update被增了,那么 add 和 update 方法就被称为切入点(类中实际被增强的方法)
通知(Advice): 指提取的非业务的功能。通知分为:前置通知、后置通知、异常通知、最终通知、环绕通知
**切面(Aspect):**把通知添加到切入点的整个过程
目标(Target): 代理的目标对象(连接点,切入点所在类AdminDao)
代理(Proxy): 向目标对象应用通知时创建的代理对象
有两种实现方式:1.xml配置方式 2.注解方式
对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程。
AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,spring中引入了一个AspectJ的aop框架.
下载 AOP 相关 jar
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.2.2.RELEASEversion>
dependency>
<import resource="classpath:aopDemo.xml">import>
基于 aspectj 的 xml 配置方式实现。
先把类交给spring管理,这样spring生成的代理对象才可以调用
<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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="myutil" class="com.ffyc.ssm.util.MyUtil">bean>
<aop:config>
<aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))"/>
<aop:aspect ref="myutil">
<aop:before method="printLog" pointcut-ref="saveAdmin">aop:before>
aop:aspect>
aop:config>
beans>
package com.ffyc.ssm.util;
/* 提取的非业务的功能称为通知
通知又分为5种: 前置通知、后置通知、异常通知、最终通知、环绕通知*/
public class MyUtil {
public void printLog(){
System.out.println("打印日志");
}
public void commit(){
System.out.println("提取事务");
}
public void exceptionAdvice(Throwable e){
System.out.println("异常通知"+e.getMessage());
}
}
package com.ffyc.ssm.dao;
@Repository(value = "adminDao")
//目标类
public class AdminDao {
@Autowired
JdbcTemplate jdbcTemplate;
/*连接点:类中可以被增强的方法,称为连接点
切入点: 类中实际被增强的方法,横切面切入的方法*/
public void saveAdmin(Admin admin){
System.out.println("保存管理员");
}
public void updateAdmin(Admin admin){
System.out.println("修改管理员");
}
}
public class Test3 {
public static void main(String[] args) {
ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
Admin admin=app.getBean("admin",Admin.class);
AdminService adminService=app.getBean("adminService",AdminService.class);
adminService.save(admin);
}
}
通知又分为5种:
前置通知:业务方法执行前调用
后置通知(after-returning):业务方法执行后调用,当方法出现异常不执行
异常通知 (after-throwing):业务方法出现异常时调用
最终通知(after):业务方法执行后调用,当方法出现异常也会执行
环绕通知,环绕通知包含前四种通知
package com.ffyc.ssm.util;
public class MyUtil {
/*ProceedingJoinPoint需要调用的方法*/
public void aroundAdvice(ProceedingJoinPoint point){
try {
System.out.println("前置通知");
point.proceed();//调用我们自己的业务方法
System.out.println("后置通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知"+throwable.getMessage());
}
System.out.println("最终通知");
}
}
<aop:config>
<aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))"/>
<aop:aspect ref="myutil">
<aop:around method="aroundAdvice" pointcut-ref="saveAdmin">aop:around>
aop:aspect>
aop:config>
1.开启自动代理
<aop:aspectj-autoproxy />
2.@Component //让spring管理生成对象
@Aspect //表明装有通知的类/切面
package com.ffyc.ssm.util;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component //让spring管理生成对象
@Aspect //表明装有通知的类/切面
public class MyUtil {
//@Before("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
//@AfterReturning("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
//@After("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
public void printLog(){
System.out.println("打印日志");
}
public void commit(){
System.out.println("提取事务");
}
//@AfterThrowing(value = "execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))",throwing = "e")
public void exceptionAdvice(Throwable e){
System.out.println("异常通知"+e.getMessage());
}
/*ProceedingJoinPoint需要调用的方法*/
@Around("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
public void aroundAdvice(ProceedingJoinPoint point){
try {
System.out.println("前置通知");
point.proceed();//调用我们自己的业务方法
System.out.println("后置通知");
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("异常通知"+throwable.getMessage());
}
System.out.println("最终通知");
}
}