Spring5学习

3 篇文章 0 订阅

Spring5学习

spring下载地址
下载5.2.6版本

入门案例 通过Spring配置文件创建对象并获取

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

导入Spring5相关包

导入最核心的四个包
在这里插入图片描述
Bean, Core, Context, Expression
在这里插入图片描述
Java工程中导入jar
在这里插入图片描述
新建配置文件bean1.xml,Spring的配置文件采用xml格式。
在这里插入图片描述

<?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">
    <!-- 配置User对象创建-->
    <bean id="user" class="com.atguigu.spring5.User"></bean>
</beans>

com.atguigu.spring下新建类User.class
在这里插入图片描述

package com.atguigu.spring5;

/**
 * @author ColdRain
 */
public class User {
    public void add() {
        System.out.println("add...");
    }
}

com.atguigu.spring.testdemo新建测试类TestSpring5.class

  • 这里要先加载Spring的配置文件,通过ApplicationContext接口,因为配置文件在包类路径下所以使用了实现类ClassPathXmlApplicationContext,后续会详细讲解;
  • 通过ApplicationContext的变量的getBean(id, class)方法获取对象实例;
package com.atguigu.spring5.testdemo;

import com.atguigu.spring5.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestSpring5 {

    @Test
    public void  testAdd() {
//        1.加载Spring配置文件, 在src文件夹下可以通过ClassPathXmlApplicationContext直接检查出配置文件
//        可选FileSystemXmlApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//        2.获取配置创建的对象
//        通过bean文件中的id值获取
        User user = context.getBean("user", User.class);

        System.out.println(user);
        user.add();
    }
}

在这里插入图片描述

IOC容器

在这里插入图片描述

IoC( Inversion of Control)

使用对象时,由主动new产生对象转换为由外部(Spring提供的容器,IoC容器)提供对象,此过程中对象创建控制权由程序转移到外部。

Spring提供了一个容器,称为IoC容器,用来充当IoC思想的外部。
IoC容器负责对象的创建、初始化等一些列工作,被创建或被管理的对象在IoC容器中统称为Bean。

DI(Dependency Injection)

在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

目的:充分解耦

  • 使用IoC容器管理bean
  • 在IoC容器内讲有依赖关系的bean进行关系绑定;

最终效果:

  • 使用对象时不仅可以直接IoC容器中获取,并且获取到bean已经绑定了的所有依赖关系。
1. 什么是IoC(Inversion of Control)控制反转

1)控制反转,将对象创建和对象之间的调用过程交给Spring管理;
2)使用IOC目的:为了耦合度降低;

举例:
在这里插入图片描述
通过工厂模式,添加中间工厂解耦UserServiceUserDao
在这里插入图片描述

IOC(BeanFactory接口)

1.IOC思想基于IOC容器完成,底层就是对象工厂;
2.Spring提供IOC容器实现两个接口:

  • BeanFactory:IOC容器基本实现,Spring内部才可以使用的接口,不提供给开发人员。
    *加载配置文件时不会创建对象,再获取对象(使用)才会创建对象。
  • ApplicationContextBeanFactory接口的子接口,由开发人员使用。
    *加载配置文件时就会进行对象的创建。
    3.ApplicationContext接口有实现类:
    在这里插入图片描述
IOC操作Bean管理(基于xml方式)

1.基于xml方式创建

<!--配置User对象创建-->
<bean id="user" class = "com.atguigu.spring5.User"></bean>

1)在Spring配置文件中,使用<bean>标签进行对象的创建,标签内添加对应的属性,例:

  • id:唯一标识。(nameid类似,name中可以使用特殊符号)
  • class:类的全路径(包类路径);

2)创建对象时,默认执行无参构造方法

DI(Dependency Injection)依赖注入,即基于xml方式注入属性

1.使用set方法注入
a.创建类,定义属性和对应的set方法

package com.atguigu.spring5;

public class Book {

    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }

    public void testBook() {
        System.out.println(this.bname + "::" + this.bauthor);
    }
}

在这里插入图片描述
b.在Spring配置文件中进行对象创建,并进行属性注入。

  • 属性注入使用<property name="属性名" value="属性值"></property>格式
<?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="book" class="com.atguigu.spring5.Book">
        <property name="bname" value="Pretty Beauty"></property>
        <property name="bauthor" value="anonym"></property>
    </bean>
</beans>
p名称空间注入(了解)

在头配置文件中加入配置xmlns:p="http://www.springframework.org/schema/p"
完整头配置如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

在进行属性注入时,可以使用p命名的形式,即
<property id="唯一标识" class="包类" p:属性名=“属性值”>
例:

<bean id="book" class="com.atguigu.spring5.Book" p:bname="Jane Eyre" p:bauthor="Charlotte"></bean>

2.使用 有参构造器 进行注入
在上面的bean1.xml文件中加入如下代码,这里不再通过<property>标签,使用<constructor-arg>标签。

  • 格式为<constructor-arg name="属性名" value="属性值"></constructor-arg>
<bean id="orders" class="com.atguigu.spring5.Orders">
     <constructor-arg name="oname" value="Computer"></constructor-arg>
     <constructor-arg name="address" value="China"></constructor-arg>
</bean>
null与特殊符号

1.null值注入,使用<null/>

<property name="address">
	<null/>
</property>

2.特殊符号注入,使用转义或者 <![CDATA[值]]>格式

<!--
	属性值包含特殊符号
	1 把<>进行转义为&lt,&gt;
	2 使用<![CDATA[值]]>
-->
<property name="address">
	<value><![CDATA[<<南京>>]]></value>
</property>
注入属性-外部bean

这里想要实现在service中调用UserDao的方法

原始方法
1.我们在包路径下新建daoservice包;
在这里插入图片描述
2.在dao下新建interface(接口)UserDao,和实现类UserDaoImpl

UserDao:

package com.atguigu.spring5.dao;

public interface UserDao {
    public void update();
}

UserDaoImpl:

package com.atguigu.spring5.dao;

public class UserDaoImpl implements UserDao {
    @Override
    public void update() {
        System.out.println("dao-update...");
    }
}

service下新建UserService

package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;
import org.junit.Test;

public class UserService {
    @Test
    public void add() {
        System.out.println("service-add...");
        UserDao userDao = new UserDaoImpl();
        userDao.update();
    }

}

在这里插入图片描述
通过外部bean注入

我们将在UserService中进行声明的UserDao变量,改为类的属性,并且设定set()函数,用于将UserDao对象传进来;

UserService:

package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;
import org.junit.Test;

public class UserService {
	//类属性
    private UserDao userDao;
    //将UserDao对象传入的set()函数
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add() {
        System.out.println("service-add...");
        //直接调用类属性的UserDao对象的方法
        userDao.update();
    }

}

我们在bean中进行UserDaoUserService对象的建立,我们新建一个配置文件src/bean2.xml:

<?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="userService" class="com.atguigu.spring5.service.UserService">
        <!--注入userDao对象
            name:set函数的参数名
            ref:通过id引用bean文件中创建的对象
        -->
        <property name="userDao" ref="userDao"></property>
    </bean>
	<!--bean在property标签的外部,这就是为什么叫外部bean注入-->
    <bean id="userDao" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>

</beans>

这里UserService直接使用了bean文件通过set()函数进行传入UserDao对象,同样是使用<property>设置传参,这里使用了新的属性ref,引用bean内声明对象的id,格式为:

<bean id="唯一标识,可以看成对象名" class="包类路径">
	<property name="参数名" ref="bean内对象id"></property>
</bean>

注:这里<property>标签引用的bean对象在<property>的外部,这就是为什么叫做外部bean注入属性!

最后新建测试类TestBean.class

package com.atguigu.spring5.testdemo;

import com.atguigu.spring5.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean {
    @Test
    public void testAdd() {
    	//加载类文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
		//通过bean获取建立的对象
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
}

执行成功
在这里插入图片描述

注入属性-外部bean 和 级联赋值

外部Bean
这里新建两个类Dept.classDepartment部门类,Emp.classEmployee员工类;
Dept.class

package com.atguigu.spring5.bean;

//部门类
public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "dname='" + dname + '\'' +
                '}';
    }
}

Emp.class

package com.atguigu.spring5.bean;

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某一个部门
    private Dept dept;

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void add() {
        System.out.println(ename + "::" + gender + "::" + dept.toString());
    }
}

这里通过bean3.xml文件进行对象及属性配置
bean3.xml

<?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注入属性-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="ename" value="John"></property>
        <property name="gender" value="male"></property>
        <!--对象引用参数-->
        <property name="dept">
            <!--内部bean书写,声明建立对象-->
            <bean id="dept" class="com.atguigu.spring5.bean.Dept">
                <!--调用Dept类的Set()方法-->
                <property name="dname" value="Security"></property>
            </bean>
        </property>
    </bean>

</beans>

这里使用的内部bean注入属性的方式,格式为:

<bean id="唯一标识/对象名" class="包类路径">
	<!--这里传参需要一个对象-->
	<property name="set()参数名">
		<!--内部bean,新建一个对象-->
		<bean id="唯一标识/对象名" class="包类路径">
			<!--这里可以套娃,如果对象有属性并且有set()函数可以继续使用<property>标签进行赋值-->
			<property name="set()参数名" value="参数值"></property>
			...
		</bean>
	</property>
</bean>

级联赋值
bean4.xml

<?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注入属性-->
    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="ename" value="John"></property>
        <property name="gender" value="male"></property>
        <!--对象引用参数-->
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
        <!--这里是将上面传入的dept对象,再获取出来对dept的dname属性进行再赋值,所以需要Emp的Dept属性有get()方法-->
        <property name="dept.dname" value="Techology"></property>
    </bean>

    <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        <property name="dname" value="Finance"></property>
    </bean>

</beans>

这里注意需要再Emp.class中对Dept属性添加get()方法!

package com.atguigu.spring5.bean;

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某一个部门
    private Dept dept;
    ...
    public Dept getDept() {
        return dept;
    }

    public void add() {
        System.out.println(ename + "::" + gender + "::" + dept.toString());
    }
}

这里是将上面传入的dept对象,再获取出来对deptdname属性进行再赋值,所以需要Emp,classDept属性有get()方法。

注入属性-集合注入

使用bean进行集合类属性的注入,首先在类里设置集合类属性,并设置set()方法;

package com.atguigu.spring5.collectiontype;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Student {
    // 1 数组类型属性
    private String[] courses;

    // 2 list集合类型属性
    private List<String> list;

    // 3 map集合类型属性
    private Map<String, String> map;

    // set集合
    private Set<String> set;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void test() {
        System.out.println(Arrays.toString(courses));
        System.out.println(list);
        System.out.println(map);
        System.out.println(set);

    }
}

之后在bean1xml文件中进行配置。

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1 集合类型属性注入-->
    <bean id="student" class="com.atguigu.spring5.collectiontype.Student">
        <!--数组类型属性注入-->
        <property name="courses">
            <!--可以使用<list>和<array>-->
            <list>
                <value>Java</value>
                <value>Database</value>
            </list>
        </property>

        <property name="list">
            <array>
                <value>John</value>
                <value>Tom</value>
            </array>
        </property>
        
        <property name="map">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="PHP" value="php"></entry>
            </map>
        </property>
        
        <property name="set">
            <set>
                <value>Mysql</value>
                <value>Redis</value>
            </set>
        </property>
    </bean>
    
</beans>

集合类属性的配置在<property>标签里加:

  • 数组[]List<E>:
<property name="属性名">
	<list>/<array>
		<value></value>
		<value><值/value>
		...
		
		<!-- 若存入为对象引用 -->
		<ref bean="beanid"></ref>
		...
	</list>/</array>
</property>

这里要提一句,若List要存入的是对象引用,那么可以使用<ref bean="beanid">进行注入;

  • Map
<property name="属性名">
	<map>
		<entry key="KEY" value="VAL"></entry>
		<entry key="KEY" value="VAL"></entry>
		...
	</map>
</property>
  • Set:
<property name="属性名">
	<set>
		<value></value>
		<value></value>
		...
	</set>
</property>
注入属性-集合提取为公共独立部分

上一部分内容讲了如何在属性标签<property>中注入集合,如果集合会被多处用到,我们可以将其提取为独立公共的配置(有自己的id);

1.修改头文件,添加了xmlns:util="http://www.springframework.org/schema/util", http://www.springframework.org/schema/util/spring-util.xsd(在xsi:schemaLocation中)。

<?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:p="http://www.springframework.org/schema/p"
       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">

2.配置文件bean.xml中,添加集合配置,使用<util:list id="唯一标识">标签:

<util:list id="bookList">
        <value>Thinking Java</value>
        <value>Math</value>
        <!-- 如果集合存储的为对象内容,则可以使用<ref>标签进行对象引用 -->
        <ref bean="对象beanid"></ref>
</util:list>

<!-- 外部bean引用 -->
<bean id="book" class="com.atguigu.spring5.collectiontype.Book">
    <property name="list" ref="bookList"></property>
</bean>
FactoryBean

我们之前使用的普通的bean,在配置文件配置了什么类,返回的就是什么类的对象;

FactoryBean(工厂bean)配置文件中定义bean的类,与实际返回的类对象可以不一样,实际返回的类对象要看实现FactoryBean接口的类中是如何定义的

举例:
1.我们新建类MyBean.class,并实现接口FactoryBean<E>FactoryBean接口中有三个方法需要重写,这里我们主要写的是第一个方法getObject(),用来定义返回对象的类型。这里我们定义为返回Course类实例。

package com.atguigu.spring5.factorybean;

import com.atguigu.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<Course> {

    //定义返回对象类型bean
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("BeanFactory");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

2.我们在配置文件中配置类实例,这里配置了类MyBean.class

<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
</bean>

3.我们在代码通过bean获取对象实例,虽然配置文件中写的是类MyBean,但是我们实际获取的Course类!

@Test
public void test3() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");

    Course myBean = context.getBean("myBean", Course.class);
    System.out.println(myBean);
}
设置通过Bean获取的实例是单例还是多例

我们默认通过Bean获取多个对象是单例的,例:
bean.xml:

<bean id="book" class="com.atguigu.spring5.collectiontype.Book">
    <property name="list" ref="bookList"></property>
</bean>
@Test
public void testCollection2() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");

    Book book1 = context.getBean("book", Book.class);
    Book book2 = context.getBean("book", Book.class);
    System.out.println(book1);
    System.out.println(book2);
}

结果获取的实例都是同一对象。
在这里插入图片描述
在Spring配置文件中,<bean>标签的scope属性可以设置单实例还是多实例。
scope有两个属性值:

  • 默认值:singleton表示单实例对象;
  • prototype表示多实例对象;

这里我们将上述代码修改为多实例:

<bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype">
    <property name="list" ref="bookList"></property>
</bean>

获取到的对象为不同实例。
在这里插入图片描述
scope设置为singletonprototype区别

  • singleton为单实例,prototype为多实例;
  • 设置为singleton时,加载Spring配置文件时就会创建单实例对象。
    设置为prototype时,加载Spring配置文件时并不会创建对象,而是在调用getBean()方法时创建多实例 对象;

在这里插入图片描述

xml自动装配

自动装配autowire: 根据指定装配规则(属性名称byName属性类型byType),Spring自动将匹配的属性值进行注入。

格式:

<bean id="唯一标识" class="包类路径" autowire="byName/byType"
>
  • byName:自动注入属性的bean id要与类中属性名保持一致;
  • byType:根据属性的类型自动注入,但是如果存在多个相同类型的属性,则无法正常注入。

实例:
包类路径com.atguigu.spring5.autowire下新建两个类Department.classEmployee.class:

package com.atguigu.spring5.autowire;

public class Department {
}

package com.atguigu.spring5.autowire;

public class Employee {
	//beanid要与属性名称保持一致;
    private Department department;

    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "department=" + department +
                '}';
    }
}

配置文件bean.xml

<!--自动装配-->
    <bean id="emp" class="com.atguigu.spring5.autowire.Employee" autowire="byType">
        <!--手动装配:<property name="department" ref="dept"></property>-->
    </bean>

    <bean id="department" class="com.atguigu.spring5.autowire.Department"></bean>

在这里插入图片描述

xml配置外部属性文件

例,在Spring配置文件配置数据库信息;

首先导入druid.jar/lib下,之后在project structure中添加druid包;

1.我们可以在配置文件中直接配置数据库信息

<beans 
    <!--直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

2.通过引入外部文件进行配置
新建src\jdbc.properties数据库配置文件:

prop.diverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.username=root
prop.password=root

这里要先加入新的头连接:
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"

在配置文件中导入外部文件后,就可以直接引用文件中的配置值,格式为${文件配置名称}

<!--引入外部文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>

 <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>
注解方式配置bean实例对象

annotation注解

1.注解是代码特殊标记,格式为@annotation(name=value, ...)
2.注解作用在类、方法、属性上面;
3.使用注解可简化xml配置;

Spring针对Bean创建对象提供的注解

  • @Component
  • @Service
  • @Controller
  • @Repository

上述四个注解的功能是一样的,只是写法不同,都可以用来创建bean实例。

例:
引入依赖
在这里插入图片描述
在配置文件bean.xml添加组件扫描,这里使用的是<context>组件需要引入相应头文件。

<context:component-scan base-package="com.atguigu"></context:component-scan>

这里扫描的是com.atguigu包下的所有注解,如果想要扫描多个包也可以通过,分隔。

<!--扫描多个包,可一个用“,”隔开-->
<context:component-scan base-package="com.atguigu.spring5.dao, com.atguigu.spring5.service"></context:component-scan>

类上的注解格式为@Component/Controller/Repository/Service,不添加(value="beanid")默认beanid为类的首字母小写名称。

注解实际上就相当于在配置文件中的<bean id="..." class="..."></bean>

我们在新建com.atguigu.spring5下新建包dao, service
service下新建UserService.class

// @Component, @Controller,@Repository()都可
// @Service(value="userService")//相当于<bean id="userService" class="...">
@Repository
public class UserService {

    public void add() {
        System.out.println("service add...");
    }
}

我们在测试类中获取bean实例

public class TestSpring5Demo1 {

    @Test
    public void testService() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

}

获取成功
在这里插入图片描述
开启组件扫描细节配置
Spring配置文件中,可以对组件扫描进行细化配置,我们设置<context:component-scan>中的user-default-filters="false"后,可以自定义注解过滤器。

<context:include-filter>只扫描定义的注解;

<context:component-scan base-package="com.atguigu" use-default-filters="true" >
	<!-- include定义要扫描哪些注释,这里只扫描Controller注释 -->
   	<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<context:exclude-filter>扫描配置中注解以外的所有注解;

 <context:component-scan base-package="com.atguigu" use-default-filters="true" >
   	<!-- 扫描Repository以外的所有注解 -->
	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
 </context:component-scan>
注解方式实现属性注入

属性注入注释: 通过anotation自动注入<property>标签

1.引用对象属性,我们可以在类属性上添加如下注解,以实现自动注入属性对象:

  • @Autowired:根据属性类型自动注入;
  • @Qualifier(value="beanid"):根据指定名称(bean id)进行注入,使用时必须和@Autowired连用;
  • @Resource选加(name="beanid"):既可以根据属性类型自动注入,也可以根据指定名称注入;

2.基本类型属性注入@Value(value="注入值")

例,我们在dao包新建接口UserDao与实现类UserDaoImpl
UserDao:

package com.atguigu.spring5.dao;

public interface UserDao {
    public void add();
}

UserDaoImpl

package com.atguigu.spring5.dao;

import org.springframework.stereotype.Repository;
//可以主动设定beanid,也可以不设置采用默认beanid=userDaoImpl
@Repository(value="userDaoImpl1")
public class UserDaoImpl implements UserDao {

    @Override
    public void add() {
        System.out.println("UserDaoImpl add ...");
    }
}

UserServiceUserDao userDao属性添加@Autowired注释

package com.atguigu.spring5.service;

// @Component, @Controller,@Repository()都可
// @Service(value="userService")//相当于<bean id="userService" class="...">
@Service
public class UserService {

    //定义dao类型属性
    //不需要添加 set() 方法
    //添加注入属性注解 @Autowired,通过类型自动注入
    @Autowired
    //也可以通过指定beanid注入
    //@Autowired
    //@Qualifier(value="userDaoImpl1")
    //也可以通过
    //@Resource 可以指定beanid + (name="userDaoImpl1")
    private UserDao userDao;
	
	//基本类型属性注入
    @Value(value="Joey")
    private String userName;

    public void add() {
        System.out.println("service add...");
        System.out.println("userName + " + userName);
        userDao.add();
    }
}

测试:

public class TestSpring5Demo1 {

    @Test
    public void testService() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

}

成功注入UserDao userDaoString useName属性!在这里插入图片描述

完全注解开发

通过注解@Configuration @ CompoenetScan(basePackages = {"包路径"})实现配置文件的注解扫描

1.创建配置类,代替xml配置文件。在com.atguigu.spring5.config包下新建SpringConfig.class类。

package com.atguigu.spring5.config;

@Configuration
@ComponentScan(basePackages = {"com.atguigu"})
//相当于配置文件中的<context:component-scan base-package="com.atguigu"></context:component-scan>
public class SpringConfig {
}

2.编写测试类,测试类获取配置文件和之前也不一样。
需要通过类AnnotationConfigApplicationContext(配置类)进行配置。

@Test
public void testService2() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println(userService);
    userService.add();
}

测试成功!
在这里插入图片描述

Bean的生命周期

1.通过类的无参构造器创建bean实例;

2.通过类的set()函数设置bean实例对象的属性值<property>和其他引用<ref>

初始化之前执行的方法:postProcessBeforeInitialization; (需配置后置处理器BeanPostProcessor.class)

3.调用bean的初始化方法;(需要配置初始化方法<bean init-method="初始化方法">

初始化之后执行的方法:postProcessAfterInitialization; (需配置后置处理器)

4.获取bean的实例对象; ApplicationContext.getBean()

5.当容器关闭,调用bean的销毁方法;<bean destroy-method="销毁方法">

Bean的生命周期主要为五个步骤,但是如果配置了后置处理器在初始化方法前和初始化方法后增加了两个步骤,一共七个步骤。

后置处理器是全局生效的,配置好后对配置文件中所有Bean对象都生效!

实例演示:
在包路径com.atguigu.spring5.bean新建类Orders.class:

package com.atguigu.spring5.bean;

public class Orders {

    //无参构造器
    public Orders() {
        System.out.println("Firstly, 执行无参数构造器");
    }
	//属性
    private String oname;
	
	//set()方法给bean实例注入属性或引用
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("Secondly, 调用set()方法设置属性值");
    }

    //创建bean初始化方法
    public void initMethod() {
        System.out.println("Thirdly, 执行初始化方法");
    }
	
	//bean销毁方法
    public void destoryMethod() {
        System.out.println("Fivethly,销毁bean对象");
    }

}

配置后置处理器,包路径com.atguigu.spring5.bean下新建MyBeanPost.class,并实现BeanPostProcessor接口,重写其中的两个方法postProcessBeforeInitialization(), postProcessAfterInitialization()

package com.atguigu.spring5.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization:在初始化之前执行");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization:在初始化之后执行");
        return bean;
    }
}

配置src/bean4.xml配置文件

<?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:p="http://www.springframework.org/schema/p"
       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对象配置 -->
    <bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destoryMethod">
        <property name="oname" value="Phone"></property>
    </bean>
	<!-- 后置处理器,全局bean生效 -->
    <bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
    
</beans>

在测试类TestSpringDemo.class中,测试bean对象的生命周期

 @Test
public void test4() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");

    Orders orders = context.getBean("orders", Orders.class);
    System.out.println("Fourthly,获取bean对象");
    System.out.println(orders);

    //手动销毁bean实例
    ((ClassPathXmlApplicationContext)context).close();
}

效果:
在这里插入图片描述

AOP

动态代理

AOP底层使用动态代理
有两种情况使用动态代理:

  • 有接口情况,使用JDK动态代理
    创建接口实现类对象,增强类的方法。
    在这里插入图片描述

  • 没有接口情况,使用CGLIB动态代理
    创建子类的代理对象,增强类的方法。
    在这里插入图片描述

AOP使用JDK动态代理实例

我们有一个接口interfaceUserDao

package com.atguigu.spring5;

public interface UserDao {
    public int add(int a, int b);
}

UserDaoImpl.class实现UserDao

package com.atguigu.spring5;

public class UserDaoImpl implements UserDao {

    @Override
    public int add(int a, int b) {
        System.out.println("adding");
        return a + b;
    }
}

我们要对接口实现类UserDaoImpl.classadd()方法实现增强。
创建接口实现类UserDaoImpl代理类JDKProxy.class

在代理类中,我们要对实现类的方法进行加强,我们要通过Proxy.newProxyInstance(ClassLoader, interface[], InvocationHandler)方法生成代理类实例。
在这里插入图片描述
这个方法用于返回指定接口的代理类实例,该接口将方法调用分配给指定的调用处理程序。
参数Parameters:
1.ClassLoader:类加载器;
2.interfaces[]:增强方法所在类的接口列表,支持多接口;
3.InvocationHandler:需要实现这个接口,创建代理对象,写增强部分。

package com.atguigu.spring5;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        //匿名类创建方式
        // Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
        //     @Override
        //     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //         return null;
        //     }
        // })
	
        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);
    }
}

//有名创建代理类实现InvocationHandler接口
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 InvocationTargetException, IllegalAccessException {
        //    方法之前
        System.out.println("Before running method: " + method.getName() + ". parameters: " + Arrays.toString(args));
        //    被增强的方法执行
        Object res = method.invoke(obj, args);
        //    方法之后
        System.out.println("After method finished: " + obj);

        return res;
    }
}


动态增强成功
在这里插入图片描述

AOP术语

1.连接点

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

2.切入点

实际被真正增强的方法,称为切入点。

3.通知(增强)

实际增强的逻辑部分成为通知(增强)。

通知类型:

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知

4.切面

将通知应用至切入点的过程。

AspectJ注解

开启AspectJ通过注解方式生成代理对象。
在配置文件中,开启注解扫描<context:component-scan>Aspect

<?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 http://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">
    
    <!-- 开启注解扫描   -->
    <context:component-scan base-package="com.atguigu.spring5.aopanno"></context:component-scan>

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

新建User.class类,通过@Component注解建立bean实例对象(相当于<bean id='user' class='包类路径'></bean>);

@Component
public class User {
    public void add() {
        System.out.println("add......");
    }
}

新建代理类UserProxy.class,通过@Component新建bean实例对象,再添加@Aspect注解生成代理对象;

通知注解配合切入点表达式进行类的增强。
通过切入点表达式,知晓对哪个类的哪个方法进行增强。
语法:execution([权限修饰符][返回类型][类全路径][方法名称][参数列表])
例1:对com.atguigu.dao.BookDao类中的add方法进行增强
execution(* com.atguigu.dao.BookDao.add(..)
例2:对com.atguigu.dao.BookDao类中的所有方法进行增强
execution(* com.atguigu.dao.BookDao.*(..)

@Component
@Aspect//生成代理对象
public class UserProxy {
    //前置通知注解,配合切入点表达式对User类的add方法进行增强。
    @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void before() {
        System.out.println("before.....");
    }
}

最后测试代理类是否完成增强

public class TestAop {

    @Test
    public void testAopAnno() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        User user = context.getBean("user", User.class);
        user.add();
    }
}

在这里插入图片描述
通知类型注解有:

  • @Before前置通知
  • @After最终通知,无论是否有异常都会通知
  • @AfterThrowing异常通知,如有异常这就是最后的通知,后两个通知都不会执行了;
  • @AfterReturning后置通知(返回通知)
  • @Around环绕通知

相同切入点抽取

我们上述使用切入点表达式execution([权限修饰符][返回类型][类全路径][方法名称][参数列表])来进行选择切入点,如果多个通知共用同样的切入点,可以对切入点进行一个抽取:@Pointcut(value = "execution(* 切入点)")注释在代理类的一个方法上,这个方法名就是抽取出的切入点。

例,我们对之前的User.add()方法这个切入点进行抽取
UserProxy.class

@Component
@Aspect//生成代理对象
public class UserProxy {
	//抽取切入点
    @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo() {

    }
	//使用@Pointcut注释的方法名
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("before.....");
    }
}

增强类优先级

多个增强类对同一个方法进行了增强,可以通过在代理类上添加注解@Order(数字),数字越小优先级越高。

例,我们新建代理类PersonProxy.class,也对User.add()方法进行增强,这时有两个代理类对这个方法进行增强了,我们通过@Order(数字)进行定义优先级。

PersonProxy.class

@Component
@Aspect
@Order(1)
public class PersonProxy {

    @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add())")
    public void afterRetuning() {
        System.out.println("Person Before...");
    }
}

UserProxy.class

@Component
@Aspect//生成代理对象
@Order(3)
public class UserProxy {
//抽取切入点
    @Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo() {

    }
    
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("before.....");
    }
}

测试:
在这里插入图片描述

JdbcTemplate

概念

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

如何引用

引入依赖包
在这里插入图片描述Spring配置文件中,配置数据库连接池。並配置JdbcTemplate对象,注入DataSource
bean.xml

<?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 http://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">
    <!--开启组件扫描-->
    <context:component-scan base-package="com.atguigu"></context:component-scan>

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

    <!-- JDBCTemplate对象   -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--注入DataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
JdbcTemplate操作数据库

dao包进行数据库的操作,使用JdbcTemplate对象里面update方法实现添加各种对数据库操作。

格式为:update(String sql, Object... args)
参数:
1.sql为sql语句,语句中的具体可以用代替;
2.args为参数数组,用来设置sql语句中的具体值;

添加

我们通过JdbcTemplate操作数据库进行添加操作。

首先在工程下建立如下结构:
在这里插入图片描述

entity包存储实体类Book

这里要注意,实体类中的属性信息要和数据库中的信息对应,不然会查不出数据库中的数据,并且属性要设定set与get方法。
在这里插入图片描述

package com.atguigu.spring5.entity;

public class Book {
    private String book_id;
    private String book_name;
    private String book_status;

    public void setBook_id(String book_id) {
        this.book_id = book_id;
    }

    public void setBook_name(String book_name) {
        this.book_name = book_name;
    }

    public void setBook_status(String book_status) {
        this.book_status = book_status;
    }

    public String getBook_id() {
        return book_id;
    }

    public String getBook_name() {
        return book_name;
    }

    public String getBook_status() {
        return book_status;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId='" + book_id + '\'' +
                ", BookName='" + book_name + '\'' +
                ", BookStatus='" + book_status + '\'' +
                '}';
    }
}

dao包下存储对数据库操作

BookDao.java

package com.atguigu.spring5.dao;

import com.atguigu.spring5.entity.Book;

public interface BookDao {
    void add(Book book);
}

BookDaoImpl.java

package com.atguigu.spring5.dao;

import com.atguigu.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class BookDaoImpl implements BookDao {

    // 注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(Book book) {
        String sql = "insert into t_book value(?, ?, ?)";
        // 两种写法
        // int update = jdbcTemplate.update(sql, book.getBookId(), book.getBookName(), book.getBookStatus());
        Object[] args = {book.getBook_id(), book.getBook_name(), book.getBook_status()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void updateBook(Book book) {
        String sql = "update t_book set book_name = ?, book_status = ? where book_id = ?";
        Object[] args = {book.getBook_name(), book.getBook_status(), book.getBook_id()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void delete(String id) {
        String sql = "delete from t_book where book_id = ?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }

    @Override
    public int selectCount() {
        String sql = "select count(*) from t_book";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }

    @Override
    public Book findBookInfo(String id) {
        String sql = "select * from t_book where book_name = ?";
        // System.out.println(book.toString());
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), "java");
    }

    @Override
    public List<Book> findAllBook() {
        String sql = "select * from t_book";
        List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Book.class));
        return bookList;
    }
}

service

BookService.java

package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.BookDao;
import com.atguigu.spring5.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    // 注入BookDaoImpl
    @Autowired
    private BookDao bookDao;

    public void addBook(Book book) {
        bookDao.add(book);
    }
}

测试包Test

TestBook.java

package com.atguigu.spring5.test;

import com.atguigu.spring5.entity.Book;
import com.atguigu.spring5.service.BookService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
    @Test
    public void testJdbcTemplate() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookService bookService = context.getBean("bookService", BookService.class);
        Book book = new Book();
        book.setBook_id("1");
        book.setBook_name("java");
        book.setBook_status("a");
        bookService.addBook(book);
    }
}

运行测试类,得到反馈。
在这里插入图片描述
在这里插入图片描述

更新、删除操作

对数据库的更新、删除操作同理,先在dao包中加入具体的对数据库的操作。

BookDao.java

public interface BookDao {
    void add(Book book);
    void updateBook(Book book);
    void delete(String id);
}

BookDaoImpl.java

public class BookDaoImpl implements BookDao {

    // 注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
	...
    @Override
    public void updateBook(Book book) {
        String sql = "update t_book set username = ?, ustatus = ? where user_id = ?";
        Object[] args = {book.getBookName(), book.getBookStatus(), book.getBookId()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void delete(String id) {
        String sql = "delete from t_book where user_id = ?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }

service包中添加操作。

package com.atguigu.spring5.service;
...
@Service
public class BookService {

    // 注入dao
    @Autowired
    private BookDao bookDao;
	...
    public void updateBook(Book book) {
        bookDao.updateBook(book);
    }

    public void deleteBookById(String id) {
        bookDao.delete(id);
    }
}

查找并返回对象
使用queryForObject(String sql, RowMapper<T> rowMapper, Object... args);
1.sql:sql语句;
2.RowMapper:接口,针对返回不同类型的数据完成数据封装;
3.sql语句值;

package com.atguigu.spring5.dao;

@Repository
public class BookDaoImpl implements BookDao {
	...
	@Override
    public Book findBookInfo(String id) {
        String sql = "select * from t_book where book_name = ?";
        Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), "java");
        return book;
    }
}

查找并返回对象集合
和返回对象一样,只是将返回的对象类型变成了List<对象类>

package com.atguigu.spring5.dao;

@Repository
public class BookDaoImpl implements BookDao {
	...
    @Override
    public List<Book> findAllBook() {
        String sql = "select * from t_book";
        List<Book> bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Book.class));
        return bookList;
    }
}

批量操作

批量操作,比如批量向数据库添加、修改、删除数据,都是通过JdbcTemplate.batchUpdate(String sql, List<Object[]> batchArgs);方法
1.sql:sql语句;
2.List集合,存储多条要操作的记录;

批量添加、修改、删除
BookDao.java

package com.atguigu.spring5.dao;
public interface BookDao {
	void batchAddBook(List<Object[]> batchArgs);
    void batchUpdateBook(List<Object[]> batchArgs);
    void batchDeleteBook(List<Object[]> batchArgs);
}

BookDaoImpl.java

package com.atguigu.spring5.dao;

@Repository
public class BookDaoImpl implements BookDao {
	    @Override
    public void batchAddBook(List<Object[]> batchArgs) {
        String sql = "insert into t_book value(?, ?, ?)";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }
   
    @Override
    public void batchUpdateBook(List<Object[]> batchArgs) {
        String sql = "update t_book set book_name = ?, book_status = ? where book_id = ?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }

    @Override
    public void batchDeleteBook(List<Object[]> batchArgs) {
        String sql = "delete from t_book where book_id = ?";
        int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
        System.out.println(Arrays.toString(ints));
    }

}

BookService.java

package com.atguigu.spring5.service;
@Service
public class BookService {
    // 批量添加
    public void batchAdd(List<Object[]> batchArgs) {
        bookDao.batchAddBook(batchArgs);
    }

    // 批量修改
    public void batchUpdateBook(List<Object[]> batchArgs) {
        bookDao.batchUpdateBook(batchArgs);
    }
    
    // 批量删除
    public void batchDeleteBook(List<Object[]> batchArgs) {
        bookDao.batchDeleteBook(batchArgs);
    }
}
静态代理

在这里插入图片描述

  • 静态代理角色分析

抽象角色 : 一般使用接口或者抽象类来实现

真实角色 : 被代理的角色

代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

客户 : 使用代理角色来进行一些操作 .

  • 实例:
    抽象角色:UserService接口,用户业务,抽象起来就是增删改查
package com.kuang.demo02;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

真实角色:核心功能UserServiceImpl,真实对象来完成这些增删改查操作

package com.kuang.demo02;

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }

}

代理角色:UserServiceProxy,需求来了,现在我们需要增加一个日志功能,怎么实现!

  1. 思路1 :在实现类上增加代码 【麻烦!】

  2. 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!

package com.kuang.demo02;


public class UserServiceProxy implements UserService {

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    public void log(String msg) {
        System.out.println("执行了" + msg + "方法:");
    }
}

测试访问类

public class Client {
   public static void main(String[] args) {
       //真实业务
       UserServiceImpl userService = new UserServiceImpl();
       //代理类
       UserServiceProxy proxy = new UserServiceProxy();
       //使用代理类实现日志功能!
       proxy.setUserService(userService);

       proxy.add();
  }
}
动态代理

JDK的动态代理需要了解两个核心类: InvocationHandler 和 Proxy

动态代理类ProxyInvocationHandler.class:

target是要传入的真实业务

package com.kuang.demo04;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    
    // proxy : 代理类,method : 代理类的调用处理程序的方法对象.
   // 处理代理实例上的方法调用并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);

        return result;
    }
	//新增加的业务,输出日志
    public void log(String methodName) {
        System.out.println("执行了" + methodName + "方法");
    }

}

测试类Test.class

有了动态代理类,我们可以不用单独建立代理类,可以直接通过ProxyInvocationHandler设定抽象对象来动态的获取代理对象。

package com.kuang.demo04;

import com.kuang.demo02.UserService;
import com.kuang.demo02.UserServiceImpl;

public class Test {
    public static void main(String[] args) {
        /*真实对象*/
        UserServiceImpl userService = new UserServiceImpl();
        /*代理对象的调用处理程序*/
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(userService); //设置要代理的对象
        UserService proxy = (UserService)pih.getProxy();//动态生成代理类!
        proxy.delete();
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值