Spring5学习小总结

本文根据尚硅谷王老师的Spring5视频教程总结的。z作者跟着教程全程实践,本文内容较为简略,详细内容请移步王老师视频教程。

一、概述

轻量级开源的JavaEE框架

核心部分:

​ (1)IOC:控制反转,将创建对象交给Spring管理

​ (2)AOP:面向切面,不修改源代码进行功能增强

IOC基本包:
在这里插入图片描述

二、IOC

控制反转:将创建对象和对象之间的调用过程交给Spring进行管理

使用目的:降低代码耦合度

1、IOC底层原理

xml解析、工厂模式、反射

第一步:xml配置文件,配置创建的对象(bean对象)

第二步:创建工厂类
在这里插入图片描述

2、IOC接口(BeanFactory)

IOC基于IOC容器完成,IOC容器底层即对象工厂

IOC容器实现:

​ (1)BeanFactory:加载配置文件时不会创建对象,在获取对象(使用)时才会去创建对象 (内部使用接口)

​ (2)ApplicationContext:加载配置文件时就会把配置文件中的对象创建 (开发人员使用)

3、IOC操作Bean管理

Bean管理:

​ (1)创建对象

​ (2)注入属性

基于xml方式

创建对象:

​ 在配置文件中添加bean标签,标签中添加对应属性,实现对象创建

注入属性:

​ (1)使用set方法注入

​ 类中创建对应属性set()方法—>配置文件中配置属性注入

/**
 * 演示使用set方法注入属性
 */
public class Book {
    //创建属性
    private String bname;
    private String bauthor;
    private String adderss;
    //创建属性对应的set方法
    public void setBname(String bname){
        this.bname = bname;
    }
    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }
    public void setAddress(String address) {
        this.adderss = address;
    }
    public void testDemo(){
        System.out.println(bname+" "+bauthor+" "+adderss);
    }
}


<!-- 2 set方法注入属性-->
<bean id="book" class="com.atguigu.spring5.Book">
    <!-- 使用property完成属性注入 -->
    <property name="bname" value="易筋经"></property>
    <property name="bauthor" value="达摩老祖"/>
    <!-- 属性值为空 -->
    <!--<property name="address"><null></null></property>-->
    <!-- 属性值包含特殊字符 -->
    <property name="address">
    	<value>
    		<![CDATA[<<南京>>]]>
        </value>
    </property>
</bean>

​ (2)使用有参构造函数注入

​ 类中创建对应属性有参构造方法—>配置文件中属性注入

public class Orders {
    //属性
    private String oname;
    private String address;
    //有参构造
    public Orders(String oname, String address) {
        this.oname = oname;
        this.address = address;
    }
    public void testOrders(){
        System.out.println(oname+" "+address);
    }
}

<!-- 3 有参构造注入属性 -->
<bean id="orders" class="com.atguigu.spring5.Orders">
    <constructor-arg name="oname" value="abc"></constructor-arg>
    <constructor-arg name="address" value="Chain"></constructor-arg>
</bean>

注入外部属性(默认set()方法注入)

​ 类中属性为另一个类(如service中注入dao)

​ 创建两个类service和dao—>seivice中属性为dao—>为dao创建set()方法—>配置类中创建service和dao对象—>在service的bean对象中注入dao对象

public class UserService {
    //创建UserDao类型属性,生成set方法
    private UserDao userDao;
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add....................");
        userDao.update();
        //原始方式
        //UserDao userDao = new UserDaoImpl();
        //userDao.update();
    }
}

<!-- 1 service和dao对象创建 -->
<bean id="userService" class="com.atguigu.spring5.service.UserService">
    <!--2 注入UserDao对象
    	name属性:类里面属性名称
        ref属性:创建userDao对象bean标签id值-->
    <property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

注入内部属性(默认set()方法注入)

<!-- 内部bean -->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
    <!-- 先设置两个普通的属性 -->
    <property name="ename" value="lucy"></property>
    <property name="gender" value="女"></property>
    <!-- 设置对象类型属性 -->
    <property name="dept">
        <bean id="dept" class="com.atguigu.spring5.bean.Dept">
            <property name="dname" value="安保部"></property>
        </bean>
    </property>
</bean>

注入集合属性(默认set()方法注入)

​ 创建类,定义数组、list、map、set类型属性,生成set()方法—>在配置文件中进行配置

<!-- 集合类型属性注入 -->
<bean id="stu" class="com.atgui
    <!-- 数组类型属性注入 -->
    <property name="course">
        <array>
            <value>java课程</valu
            <value>数据库课程</value
        </array>
    </property>
    <!-- list类型属性注入 -->
    <property name="list">
        <list>
            <value>张三</value>
            <value>小三</value>
        </list>
    </property>
    <!-- map类型属性注入 -->
    <property name="maps">
        <map>
            <entry key="JAVA" v
            <entry key="PHP" va
        </map>
    </property>
    <!-- set类型属性注入 -->
    <property name="set">
        <set>
            <value>MySQL</value
            <value>Redis</value
        </set>
    </property>
    <!-- 注入List集合类型,值是对象 -->
    <property name="courseList"
        <list>
            <ref bean="course1"
            <ref bean="course2"
        </list>
    </property>
</bean>

<!-- 创建多个course对象 -->
<bean id="course1" class="com.atguigu.spring5.collectiontype.Course">
    <property name="cname" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.atguigu.spring5.collectiontype.Course">
    <property name="cname" value="MyBatis框架"></property>
</bean>
基于注解方式

注解格式:@注解名称(属性名称=属性值,属性名称=属性值…)

使用目的:简化xml配置

Bean管理注解:@Controller、@Service、@Repository、@Component

创建对象:

​ 引入依赖—>开启组件扫描—>在类上面添加注解—>组件扫描细节
在这里插入图片描述

<!-- 开启组件扫描 
    1 如果扫描多个包,使用逗号隔开
    2 扫描包上层目录
    -->
<context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>
//在注解里面value可以省略不写,默认是类名称首字母小写   UserService->userService
//@Component(value = "userService")   //类似于xml文件中定义<bean id="userService" class=".."/>
@Service
//@Controller
//@Repository
public class UserService {}

在这里插入图片描述

属性注入:

​ @Autowired:根据属性类型进行自动装配

​ @Qualifier:根据名称进行注入

​ @Resource:根据属性类型或者名称进行注入

​ @Value:注入普通类型属性

​ 创建service和dao对象—>在service和dao上添加注解—>开启组件扫描

​ 在service中添加dao属性—>在属性上使用注入注解

完全注解开发

​ 创建配置类代替xml配置文件

@Configuration  //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig { }
FactoryBean

​ 普通bean:配置文件中定义的bean类型就是返回类型

​ 工厂Bean:配置文件中定义的bean类型和返回类型不一样

​ (1)创建类,让其作为工厂类,实现接口FactoryBean

​ (2)实现接口里面的方法,在实现的方法中定义返回的bean类型

bean作用域

​ 默认情况下,bean是单实例对象—意思是创建的多个实例对象,其指向的地址是一个

​ 设置多实例对象—只需在配置文件bean标签中设置scope属性为prototype

​ 区别:

​ 单实例在加载配置文件时就会创建单实例对象

​ 多实例在调用getBean方法是创建多实例对象

外部属性文件

​ (1)配置数据库信息

​ 配置德鲁伊连接池—>引入德鲁伊的依赖jar包
在这里插入图片描述

<!-- 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/userDb" />
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="username" value="root" />
    <property name="password" value="123" />
</bean>

​ (2)引入外部properties属性文件到配置文件中

​ 引入conetxt名称空间—>配置文件中使用标签引入外部属性文件

<!-- 引入外部属性文件  -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${prop.driverClass}"></property>
    <property name="url" value="${prop.url}"></property>
    <property name="username" value="${prop.username}"></property>
    <property name="password" value="${prop.password}"></property>
</bean>

三、AOP

面向切面编程,可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低。即:通过不修改源代码的方式,在主干功能里边添加新功能

1、AOP底层原理

使用动态代理

(1)有接口,使用JDK动态代理

创建接口实现类代理对象,增强类的方法

(2)无接口,使用CGLIB动态代理

创建当前类子类的代理对象,增强类的方法

JDK动态代理

(1)使用Proxy类中的方法创建代理对象

方法中的三个参数分别是类加载器、增强方法所在的类、实现这个接口的InvocationHandler

(2)编写JDK动态代理代码

创建接口,定义方法—>创建接口实现类,实现方法—>使用Proxy类创建接口代理对象—>创建代理对象代码

 // 创建接口实现类代理对象         
public class JDKProxy {     
    public static void main(String[] args) { 
		Class[] interfaces = {UserDao.class}; 
		UserDaoImpl userDao = new UserDaoImpl();         
	    UserDao dao = (UserDao)Proxy. newProxyInstance (JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); 
        int result = dao.add(1, 2);
        System. out .println("result:"+result); 
    }
}
// 创建代理对象代码 
class UserDaoProxy implements InvocationHandler {     
    //1 把创建的是谁的代理对象,把谁传递过来     
    // 有参数构造传递     
    private Object obj;     
    public UserDaoProxy(Object obj) {         
        this.obj = obj;     
    }     
    // 增强的逻辑     
    @Override     
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         
        // 方法之前         
        System. out .println("方法之前执行...."+method.getName()+" :传递的参 数..."+ Arrays. toString (args));         
        // 被增强的方法执行         
        Object res = method.invoke(obj, args);         
        // 方法之后         
        System. out .println("方法之后执行...."+obj);         return res;     
    } 
}

2、AOP术语

连接点:类里面哪些方法可以被增强,这些方法称为连接点

切入点:实际被增强的方法

通知(增强):实际增强的逻辑部分 (分类为前置、后置、环绕、异常、最终通知)

切面:把通知应用到切入点的过程

3、AOP操作(准备工作)

一般地,通过AspectJ和Spring框架一起使用进行AOP操作

基于AspectJ实现方式:xml和注解

引入AOP相关依赖
在这里插入图片描述

切入点表达式:知道对哪个类的哪个方法进行增强: execution(* [返回类型] [类全路径] 方法名称 ) :例:execution(* com.atguigu.dao.BookDao.add(…))

4、AOP操作(AspectJ注解)

—>创建类,在类里面定义方法

—>创建增强类(编写增强逻辑)

—>进行通知的配置

​ 开启注解扫描->@Component注解上面创建的类->在增强类上添加注解@Aspect->开启Aspect生成代理对象

<!-- 开启 Aspect 生成代理对象 --> 
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

—>配置不同类型的通知

​ 在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") 

—>相同的切入点的抽取

@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") 

—>有多个增强类对同一方法进行增强,设置增强类优先级

​ 增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高

—>完全使用注解开发

@Configuration 
@ComponentScan(basePackages = {"com.atguigu"}) @EnableAspectJAutoProxy(proxyTargetClass = true) 
public class ConfigAop { }

四、JdbcTemplate

Spring框架对JDBC进行封装,使用JdbcTemplate实现对数据库的操作

准备工作

—>引入相关jar包
在这里插入图片描述
在这里插入图片描述

—>配置文件中配置组件扫描和数据库连接池dataSource

—>配置JdbcTemplate对象,注入dataSource

—>创建service类和dao类,在dao中注入jdbcTemplate对象

操作数据库

//添加数据
//1 创建 sql 语句         
String sql = "insert into t_book values(?,?,?)";         
//2 调用方法实现         
Object[] args = {book.getUserId(), book.getUsername(), book.getUstatus()};         
int update = jdbcTemplate.update(sql,args); 

//修改数据
String sql = "update t_book set username=?,ustatus=? where user_id=?";     
Object[] args = {book.getUsername(), book.getUstatus(),book.getUserId()};     
int update = jdbcTemplate.update(sql, args); 

//删除数据
 String sql = "delete from t_book where user_id=?";     
int update = jdbcTemplate.update(sql, id); 

//查询表记录
String sql = "select count ( * ) from t_book";     
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);

//查询返回对象
String sql = "select * from t_book where user_id=?";     
Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id); 

//查询返回集合
String sql = "select * from t_book";
List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));

//批量添加
public void batchAddBook(List<Object[]> batchArgs) {     
    String sql = "insert into t_book values(?,?,?)";     
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
    System.out.println(Arrays.toString(ints)); 
}
//批量添加测试
List<Object[]> batchArgs = new ArrayList<>(); 
Object[] o1 = {"3","java","a"}; 
Object[] o2 = {"4","c++","b"}; 
Object[] o3 = {"5","MySQL","c"}; 
batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); 
bookService.batchAdd(batchArgs); 

//批量修改
public void batchUpdateBook(List<Object[]> batchArgs) {     
    String sql = "update t_book set username=?,ustatus=? where user_id=?";     
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);     
    System. out .println(Arrays. toString (ints)); 
} 
List<Object[]> batchArgs = new ArrayList<>(); 
Object[] o1 = {"java0909","a3","3"}; 
Object[] o2 = {"c++1010","b4","4"}; 
Object[] o3 = {"MySQL1111","c5","5"}; 
batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); 
bookService.batchUpdate(batchArgs);

//批量删除
public void batchDeleteBook(List<Object[]> batchArgs) {    
    String sql = "delete from t_book where user_id=?";     
    int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);     
    System. out .println(Arrays. toString (ints)); 
} 
List<Object[]> batchArgs = new ArrayList<>(); 
Object[] o1 = {"3"}; Object[] o2 = {"4"}; 
batchArgs.add(o1); batchArgs.add(o2); 
bookService.batchDelete(batchArgs);

五、事务管理

事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败

特性(ACID):原子性、一致性、隔离性、持久性

Spring声明式事务管理(注解)

—>配置文件中配置事务管理器并引入名称空间tx

<! -- 创建事务管理器 -- > 
<bean id="transactionManager"                        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property> 
</bean>

—>开启事务注解

<! -- 开启事务注解 -- > 
<tx:annotation-driven transactionmanager="transactionManager"></tx:annotation-driven> 

—>在所需的类或方法上添加事务注解@Transactional

—>事务管理参数配置

​ propagation:事务传播行为

​ ioslation:事务隔离级别,多事务操作之间不会产生影响,解决:脏读、不可重复读、虚(幻)读

​ timeout:超时时间

​ readOnly:是否只读

​ rollbackFor:回滚

​ noRollbackFor:不回滚

完全注解开发

@Configuration // 配置类 
@ComponentScan(basePackages = "com.atguigu") // 组件扫描 
@EnableTransactionManagement // 开启事务 
public class TxConfig {     
    // 创建数据库连接池    
    @Bean     
    public DruidDataSource getDruidDataSource() {         
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///user_db");         
        dataSource.setUsername("root");         
        dataSource.setPassword("root");         
        return dataSource;     
    }     
    // 创建 JdbcTemplate 对象     
    @Bean     
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {         
        // 到 ioc 容器中根据类型找到 dataSource         
        JdbcTemplate jdbcTemplate = new JdbcTemplate();         
        // 注入 dataSource         
        jdbcTemplate.setDataSource(dataSource); 
        return jdbcTemplate;     
    }    
    // 创建事务管理器     
    @Bean     
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);         
        return transactionManager;     
    } 
}

六、Spring5新特性

1、日志封装

引入jar包—>创建 log4j2.xml配置文件
在这里插入图片描述

<? xml version="1.0" encoding="UTF-8" ?> 
<! -- 日志级别以及优先级排序 : OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -- > 
<! -- Configuration 后面的 status 用于设置 log4j2 自身内部的信息输出,可以不设置, 当设置成 trace 时,可以看到 log4j2 内部各种详细输出 -- > 
<configuration status="INFO">     
    <! -- 先定义所有的 appender -- >     
    <appenders>         
        <! -- 输出日志信息到控制台 -- >         
        <console name="Console" target="SYSTEM_OUT">             
            <! -- 控制日志输出的格式 -- >             
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %5level %logger{36} - %msg%n"/>         </console>     
    </appenders>     
    <! -- 然后定义 logger ,只有定义 logger 并引入的 appender  appender 才会生效 -- >     
    <! -- root :用于指定项目的根日志,如果没有单独指定 Logger ,则会使用 root 作为 默认的日志输出 -- > 
    <loggers>         
        <root level="info">             
            <appender-ref ref="Console"/>         
        </root>
    </loggers>
</configuration>

2、@Nullable 注解

@Nullable 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空

3、JUnit5

引入测试依赖jar包—>使用注解创建测试类
在这里插入图片描述

@RunWith(SpringJUnit4ClassRunner.class) // 单元测试框架
@ContextConfiguration("classpath:bean1.xml") // 加载配置文件
//使用一个复合注解替代上面两个注解
//@SpringJUnitConfig(locations = "classpath:bean1.xml") 	
public class JTest4 {
    @Autowired
    private UserService userService;
    @Test
    public void test1() {
        userService.accountMoney();
    }
}

以上是JUnit4,使用JUnit5只需在导入@Test换成5的即可

4、Webflux

Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用 当前一种比较流程响应式编程出现的框架

使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻 塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现的

异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同 步,如果发送请求之后不等着对方回应就去做其他事情就是异步

阻塞和非阻塞针对被调用者,被调用者受到请求之后,做完请求任务之后才给出反馈就是阻 塞,受到请求之后马上给出反馈然后再去做事情就是非阻塞

实例:

第一步 创建 SpringBoot 工程,引入 Webflux 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

第二步 配置启动端口号

server.port=8081

第三步 创建包和相关类

//实体类
public class User {
    private String name;
    private String gender;
    private Integer age;
    public User(String name, String gender, Integer age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}

//用户操作接口
public interface UserService {
    //根据ID查询用户
    Mono<User> getUserById(int id);
    //查询所有用户
    Flux<User> getAllUser();
    //添加用户
    Mono<Void> saveUserInfo(Mono<User> user);
}

@Repository
public class UserServiceImpl implements UserService {
    //创建Map集合存储数据
    private final Map<Integer,User> users = new HashMap<>();
    public UserServiceImpl(){
        this.users.put(1,new User("lucy","nan",20));
        this.users.put(2,new User("mary","nv",30));
        this.users.put(3,new User("jack","nv",50));
    }
    //根据ID查询
    @Override
    public Mono<User> getUserById(int id) {
        return Mono.justOrEmpty(this.users.get(id));
    }
    //查询多个用户
    @Override
    public Flux<User> getAllUser() {
        return Flux.fromIterable(this.users.values());//取出集合
    }
    //添加
    @Override
    public Mono<Void> saveUserInfo(Mono<User> userMono) {
        return userMono.doOnNext(person ->{     //uesrMono中的值放到person中
            //向Map集合中放值
            int id = users.size()+1;
            users.put(id,person);
        }).thenEmpty(Mono.empty());//清空里边的值
    }
}

@RestController
public class UserController {
    @Autowired
    private UserService userService;
    //id查询
    @GetMapping("/user/{id}")
    public Mono<User> getUserId(@PathVariable int id){
        return userService.getUserById(id);
    }
    //查询所有
    @GetMapping("/user")
    public Flux<User> getUsers(){
        return userService.getAllUser();
    }
    //添加
    @PostMapping("/saveuser")
    public Mono<Void> saveUser(@RequestBody User user){
        Mono<User> userMono = Mono.just(user);
        return userService.saveUserInfo(userMono);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值