Java SSM篇4——Spring

Java SSM4——Spring

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)

Spring的优势

  • 方便解耦,简化开发
    • Spring就是一个容器,可以将所有对象创建和关系维护交给Spring管理 什么是耦合度?对象之间的关系,通常说当一个模块(对象)更改时也需要更改其他模块(对象),这就是耦合,耦合度过高会使代码的维护成本增加。要尽量解耦
  • AOP编程的支持
    • Spring提供面向切面编程,方便实现程序进行权限拦截,运行监控等功能
  • 声明式事务的支持
    • 通过配置完成事务的管理,无需手动编程
  • 方便测试,降低JavaEE API
    • 的使用 Spring对Junit4支持,可以使用注解测试
  • 方便集成各种优秀框架
    • 不排除各种优秀的开源框架,内部提供了对各种优秀框架的直接支持

1、IOC

Inverse Of Control:控制反转:配置文件(解除硬编码)+反射(解除编译器依赖)

  • 控制:在java中指的是对象的控制权限(创建、销毁)
  • 反转:指的是对象控制权由原来 由开发者在类中手动控制交由Spring管理

2、AOP

Aspect Oriented Programming:面向切面编程:动态代理(方法增强)

3、快速入门

默认为maven项目

3.1、导入依赖

<dependencies>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
</dependencies>

3.2、Spring核心配置文件

如无特殊需求,我们默认spring核心配置文件名为applicationContent.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="HelloSpring" class="club.winkto.bean.HelloSpring"></bean>
</beans>

3.3、书写简单的类

public class HelloSpring {
    public void hellospring(){
        System.out.println("hello spring!");
    }
}

3.4、测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml");
    HelloSpring hellospring = classPathXmlApplicationContext.getBean("hellospring", HelloSpring.class);
    hellospring.hellospring();
}

4、Spring API

在这里插入图片描述

BeanFactory也可以完成ApplicationContext完成的事情,为什么我们要选择ApplicationContext?

BeanFactory:在第一次调用getBean()方法时,创建指定对象的实例

ApplicationContext:在spring容器启动时,加载并创建所有对象的实例

4.1、常用实现类

  • ClassPathXmlApplicationContext 它是从类的根路径下加载配置文件 推荐使用这种
  • FileSystemXmlApplicationContext 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
  • AnnotationConfigApplicationContext 当使用注解配置容器对象时,需要使用此类来创建 spring 容器,它用来读取注解

5、Spring IOC

5.1、bean

5.1.1、基础使用
<bean id="" class=""></bean>
  • id:Bean实例在Spring容器中的唯一标识
  • class:Bean的全限定名
  • 默认情况下它调用的是类中的 无参构造函数,如果没有无参构造函数则不能创建成功
5.1.2、scope属性
<bean id="" class="" scope=""></bean>
  • singleton:单例(默认)
    • 对象创建:当应用加载,创建容器时,对象就被创建了
    • 对象运行:只要容器在,对象一直活着
    • 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
  • prototype:多例
    • 对象创建:当使用对象时,创建新的对象实例
    • 对象运行:只要对象在使用中,就一直活着
    • 对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了
5.1.3、生命周期的配置
<bean id="" class="包名.类名" init-method="指定class的方法" destroy-method="指定class的方法"></bean>
  • init-method:指定类中的初始化方法名称
  • destroy-method:指定类中销毁方法名称
5.1.4、实例化的三种方式
5.1.4.1、无参构造方法实例化

上述即是

5.1.4.2、工厂静态方法实例化
<bean id="" class="包名.类名" factory-method="指定class的方法" />
5.1.4.3、工厂静态方法实例化
<bean id="工厂类id" class="包名.类名"/>
<bean id="" factory-bean="工厂类id" factorymethod="工厂类id里的方法"/>
5.1.5、别名
5.1.5.1、alias标签
<alias name="hello" alias="hello1"></alias>
5.1.5.2、bean标签name属性
<bean id="HelloSpring" name="hello2 h2,h3;h4" class="club.winkto.bean.HelloSpring"></bean>

可写多个别名,分隔符为空格,逗号,分号均可

5.2、依赖注入(DI)

Spring 框架核心 IOC 的具体实现

5.2.1、构造方法

mapper

public interface WinktoMapper {
    void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
    public void mapper() {
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
public class WinktoServiceImpl implements WinktoService {
    private int a;
    private WinktoMapperImpl winktoMapper;
    private Object[] arrays;
    private List list;
    private Map<String,Object> map;
    private Set set;
    private Properties properties;

    public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper, Object[] arrays, List list, Map<String, Object> map, Set set, Properties properties) {
        this.a = a;
        this.winktoMapper = winktoMapper;
        this.arrays = arrays;
        this.list = list;
        this.map = map;
        this.set = set;
        this.properties = properties;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("=================");
        System.out.println(toString());
        System.out.println("=================");
        System.out.println("假装自己提交了事务");
    }

    @Override
    public String toString() {
        return "WinktoServiceImpl{" +
                "a=" + a +
                ", winktoMapper=" + winktoMapper +
                ", arrays=" + arrays +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", properties=" + properties +
                '}';
    }
}

aplicationContent.xml

    <bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
    </bean>
    <bean id="winktoService" class="club.winkto.service.WinktoServiceImpl">
        <!--<constructor-arg index="0" value="12"></constructor-arg>-->
        <!--<constructor-arg index="1" ref="winktoMapper"></constructor-arg>-->
        <!--<constructor-arg index="2">-->
        <!--    <array>-->
        <!--        <value>1</value>-->
        <!--        <ref bean="winktoMapper"></ref>-->
        <!--    </array>-->
        <!--</constructor-arg>-->
        <!--<constructor-arg index="3">-->
        <!--    <list>-->
        <!--        <value>2</value>-->
        <!--        <ref bean="winktoMapper"></ref>-->
        <!--    </list>-->
        <!--</constructor-arg>-->
        <!--<constructor-arg index="4">-->
        <!--    <map>-->
        <!--        <entry key="name" value="zhangsan"></entry>-->
        <!--        <entry key="service" value-ref="winktoMapper"></entry>-->
        <!--    </map>-->
        <!--</constructor-arg>-->
        <!--<constructor-arg index="5">-->
        <!--    <set>-->
        <!--        <value>3</value>-->
        <!--        <ref bean="winktoMapper"></ref>-->
        <!--    </set>-->
        <!--</constructor-arg>-->
        <!--<constructor-arg index="6">-->
        <!--    <props>-->
        <!--        <prop key="name">zhangsan</prop>-->
        <!--    </props>-->
        <!--</constructor-arg>-->
        <constructor-arg name="a" value="12"></constructor-arg>
        <constructor-arg name="winktoMapper" ref="winktoMapper"></constructor-arg>
        <constructor-arg name="arrays">
            <array>
                <value>1</value>
                <ref bean="winktoMapper"></ref>
            </array>
        </constructor-arg>
        <constructor-arg name="list">
            <list>
                <value>2</value>
                <ref bean="winktoMapper"></ref>
            </list>
        </constructor-arg>
        <constructor-arg name="map">
            <map>
                <entry key="name" value="zhangsan"></entry>
                <entry key="service" value-ref="winktoMapper"></entry>
            </map>
        </constructor-arg>
        <constructor-arg name="set">
            <set>
                <value>3</value>
                <ref bean="winktoMapper"></ref>
            </set>
        </constructor-arg>
        <constructor-arg name="properties">
            <props>
                <prop key="name">zhangsan</prop>
            </props>
        </constructor-arg>
    </bean>
</beans>

测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml");
    WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
    winktoService.service();
}
5.2.2、set

mapper

public interface WinktoMapper {
    void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
    public void mapper() {
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
public class WinktoServiceImpl implements WinktoService {
    private int a;
    private WinktoMapperImpl winktoMapper;
    private Object[] arrays;
    private List list;
    private Map<String,Object> map;
    private Set set;
    private Properties properties;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public WinktoMapperImpl getWinktoMapper() {
        return winktoMapper;
    }

    public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
        this.winktoMapper = winktoMapper;
    }

    public Object[] getArrayList() {
        return arrays;
    }

    public void setArrayList(Object[] arrays) {
        this.arrays = arrays;
    }

    public List getList() {
        return list;
    }

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

    public Map<String, Object> getMap() {
        return map;
    }

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

    public Set getSet() {
        return set;
    }

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

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("=================");
        System.out.println(toString());
        System.out.println("=================");
        System.out.println("假装自己提交了事务");
    }

    @Override
    public String toString() {
        return "WinktoServiceImpl{" +
                "a=" + a +
                ", winktoMapper=" + winktoMapper +
                ", arrays=" + arrays +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                ", properties=" + properties +
                '}';
    }
}

aplicationContent.xml

<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl">
    <property name="a" value="12"></property>
    <property name="winktoMapper" ref="winktoMapper"></property>
    <property name="arrayList">
        <array>
            <value>1</value>
            <ref bean="winktoMapper"></ref>
        </array>
    </property>
    <property name="list">
        <list>
            <value>2</value>
            <ref bean="winktoMapper"></ref>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="name" value="zhangsan"></entry>
            <entry key="service" value-ref="winktoMapper"></entry>
        </map>
    </property>
    <property name="set">
        <set>
            <value>3</value>
            <ref bean="winktoMapper"></ref>
        </set>
    </property>
    <property name="properties">
        <props>
            <prop key="name">zhangsan</prop>
        </props>
    </property>
</bean>

测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml");
    WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
    winktoService.service();
}
5.2.3、p命名空间(简单示范)

导入约束

xmlns:p="http://www.springframework.org/schema/p"

mapper

public interface WinktoMapper {
    void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
    public void mapper() {
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
public class WinktoServiceImpl implements WinktoService {
    private WinktoMapperImpl winktoMapper;

    public WinktoMapperImpl getWinktoMapper() {
        return winktoMapper;
    }

    public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
        this.winktoMapper = winktoMapper;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("假装自己提交了事务");
    }
}

aplicationContent.xml

  • 对于bean引用用p:xxx-ref
  • 否则使用p:xxx
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" p:winktoMapper-ref="winktoMapper">
</bean>

测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml");
    WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
    winktoService.service();
}
5.2.4、c命名空间(简单示范)

导入约束

xmlns:c="http://www.springframework.org/schema/c"

mapper

public interface WinktoMapper {
    void mapper();
}
public class WinktoMapperImpl implements WinktoMapper {
    public void mapper() {
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
public class WinktoServiceImpl implements WinktoService {
    private WinktoMapperImpl winktoMapper;

    public WinktoMapperImpl getWinktoMapper() {
        return winktoMapper;
    }

    public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
        this.winktoMapper = winktoMapper;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("假装自己提交了事务");
    }
}

aplicationContent.xml

  • 对于bean引用用c:xxx-ref
  • 否则使用c:xxx
  • c命名空间可以额外使用c:_0-ref
<bean id="winktoMapper" class="club.winkto.mapper.WinktoMapperImpl">
</bean>
<!--<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" c:winktoMapper-ref="winktoMapper">-->
<!--</bean>-->
<bean id="winktoService" class="club.winkto.service.WinktoServiceImpl" c:_0-ref="winktoMapper">
</bean>

测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml");
    WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
    winktoService.service();
}

5.3、配置文件模块化

5.3.1、配置文件并列
ClassPathXmlApplicationContext classPathXmlApplicationContext =
            new ClassPathXmlApplicationContext("applicationContent.xml","beans.xml");
5.3.2、主从配置文件

在applicationContent.xml导入beans.xml

<import resource="beans.xml"/>

6、Spring注解开发(IOC部分)

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代 替xml配置文件可以简化配置,提高开发效率

开启注解扫描

<!--注解的组件扫描-->
<context:component-scan base-package="club.winkto"></context:component-scan>

6.1、注册bean

注解说明
@Component使用在类上用于实例化Bean
@Controller使用在web层类上用于实例化Bean
@Service使用在service层类上用于实例化Bean
@Repository使用在dao层类上用于实例化Bean

6.2、依赖注入

注解说明
@Autowired使用在字段上用于根据类型依赖注入(先根据type,类型不唯一根据name自动装配的)
@Qualifier结合@Autowired一起使用,根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,按照名称进行注入(很少用且jdk11在spring核心包不包含此注解)
@Value注入普通属性(也可以注入spring配置文件里的其他普通属性使用${},上面三个注入引用类型)

6.3、初始销毁

注解说明
@PostConstruct使用在方法上标注该方法是Bean的初始化方法
@PreDestroy使用在方法上标注该方法是Bean的销毁方法

6.4、新注解

注解说明
@Configuration用于指定当前类是一个Spring 配置类,当创建容器时会从该类上加载注解
@Bean使用在方法上,标注将该方法的返回值存储到 Spring 容器中
@PropertySource用于加载 properties 文件中的配置
@ComponentScan用于指定 Spring 在初始化容器时要扫描的包
@Import用于导入其他配置类

6.5、注解快速入门

mapper

public interface WinktoMapper {
    void mapper();
}
@Repository("winktoMapper")
public class WinktoMapperImpl implements WinktoMapper {
    public void mapper() {
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
@Service("winktoService")
public class WinktoServiceImpl implements WinktoService {
    @Value("12")
    private int a;
    @Autowired
    private WinktoMapperImpl winktoMapper;

    public WinktoServiceImpl() {
    }

    public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper) {
        this.a = a;
        this.winktoMapper = winktoMapper;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public WinktoMapperImpl getWinktoMapper() {
        return winktoMapper;
    }

    public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
        this.winktoMapper = winktoMapper;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("=================");
        System.out.println(toString());
        System.out.println("=================");
        System.out.println("假装自己提交了事务");
    }

    @Override
    public String toString() {
        return "WinktoServiceImpl{" +
                "a=" + a +
                ", winktoMapper=" + winktoMapper +
                '}';
    }
}

aplicationContent.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:c="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <!--注解的组件扫描-->
    <context:component-scan base-package="club.winkto"></context:component-scan>
</beans>

测试

@Test
public void test(){
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
        new ClassPathXmlApplicationContext("applicationContent.xml");
    WinktoService winktoService = classPathXmlApplicationContext.getBean("winktoService", WinktoService.class);
    winktoService.service();
}

6.6、纯注解开发

导入依赖

<dependencies>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
</dependencies>

mapper

public interface WinktoMapper {
    void mapper();
}
@Repository("winktoMapper")
public class WinktoMapperImpl implements WinktoMapper {
    @Value("${name}")
    private String name;
    public void mapper() {
        System.out.println(name);
        System.out.println("假装自己有了数据库查询");
    }
}

service

public interface WinktoService {
    void service();
}
@Service("winktoService")
public class WinktoServiceImpl implements WinktoService {
    @Value("12")
    private int a;
    @Autowired
    private WinktoMapperImpl winktoMapper;

    public WinktoServiceImpl() {
    }

    public WinktoServiceImpl(int a, WinktoMapperImpl winktoMapper) {
        this.a = a;
        this.winktoMapper = winktoMapper;
    }

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public WinktoMapperImpl getWinktoMapper() {
        return winktoMapper;
    }

    public void setWinktoMapper(WinktoMapperImpl winktoMapper) {
        this.winktoMapper = winktoMapper;
    }

    public void service() {
        System.out.println("假装自己开启了事务");
        winktoMapper.mapper();
        System.out.println("=================");
        System.out.println(toString());
        System.out.println("=================");
        System.out.println("假装自己提交了事务");
    }

    @Override
    public String toString() {
        return "WinktoServiceImpl{" +
                "a=" + a +
                ", winktoMapper=" + winktoMapper +
                '}';
    }
}

config

@Configuration
@PropertySource("classpath:database.properties")
public class WinktoMapperConfig {
    @Value("${name}")
    private String name;
}
@Configuration
@ComponentScan("club.winkto")
@Import(WinktoMapperConfig.class)
public class WinktoConfig {
    @Bean
    public ObjectMapper objectMapper(){
        return new ObjectMapper();
    }
}

测试

@Test
public void test() throws JsonProcessingException {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = 
        new AnnotationConfigApplicationContext(WinktoConfig.class);
    WinktoService winktoService = annotationConfigApplicationContext.getBean("winktoService", WinktoService.class);
    ObjectMapper objectMapper = annotationConfigApplicationContext.getBean("objectMapper", ObjectMapper.class);
    System.out.println(objectMapper.writeValueAsString(winktoService));
    winktoService.service();
}

6.7、Spring整合junit

导入依赖

<dependencies>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!--spring-test-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.9</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
</dependencies>

修改Test类

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(value = {"classpath:applicationContext.xml"})
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
    @Autowired
    private WinktoService winktoService;
    @Autowired
    private ObjectMapper objectMapper;
    @Test
    public void test() throws JsonProcessingException {
        System.out.println(objectMapper.writeValueAsString(winktoService));
        winktoService.service();
    }
}

7、动态代理

7.1、JDK动态代理

基于接口的动态代理技术:利用拦截器(必须实现invocationHandler)加上反射机制生成 一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,从而实现方法增强

在这里插入图片描述

7.2.1、JDK动态代理实现

service

public interface CRUD {
    void select();
    void insert();
    void update();
    void delete();
}
@Service
public class CRUDService implements CRUD {
    public void select() {
        System.out.println("假装自己执行了select");
    }

    public void insert() {
        System.out.println("假装自己执行了insert");
    }

    public void update() {
        System.out.println("假装自己执行了update");
    }

    public void delete() {
        System.out.println("假装自己执行了delete");
    }
}

config

@Configuration
@ComponentScan("cn.winkto")
public class WinktoConfig {
    @Bean("objectMapper")
    public ObjectMapper getObjectMapper(){
        return new ObjectMapper();
    }
}

代理

@Component
public class JDKProxy {
    public Object proxy(final CRUDService crudService){
        return  Proxy.newProxyInstance(crudService.getClass().getClassLoader(), crudService.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理前");
                Object invoke = method.invoke(crudService, args);
                System.out.println("代理后");
                return invoke;
            }
        });
    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
    @Autowired
    private JDKProxy jdkProxy;
    @Autowired
    private CRUDService crudService;
    @Test
    public void test(){
        CRUD proxy = (CRUD) jdkProxy.proxy(crudService);
        proxy.select();
    }
}

7.2、CGLIB代理

基于父类的动态代理技术:动态生成一个要代理的子类,子类重写要代理的类的所有不是 final的方法。在子类中采用方法拦截技术拦截所有的父类方法的调用,顺势织入横切逻辑,对方法进行 增强

在这里插入图片描述

7.2.1、CGLIB代理的实现

service

public interface CRUD {
    void select();
    void insert();
    void update();
    void delete();
}
@Service
public class CRUDService implements CRUD {
    public void select() {
        System.out.println("假装自己执行了select");
    }

    public void insert() {
        System.out.println("假装自己执行了insert");
    }

    public void update() {
        System.out.println("假装自己执行了update");
    }

    public void delete() {
        System.out.println("假装自己执行了delete");
    }
}

config

@Configuration
@ComponentScan("cn.winkto")
public class WinktoConfig {
    @Bean("objectMapper")
    public ObjectMapper getObjectMapper(){
        return new ObjectMapper();
    }
}

代理

@Component
public class CglibProxy {
    public Object proxy(final CRUDService crudService){
        return Enhancer.create(crudService.getClass(), new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("代理前");
                Object invoke = method.invoke(crudService, objects);
                System.out.println("代理后");
                return invoke;
            }
        });
    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
    @Autowired
    private JDKProxy jdkProxy;
    @Autowired
    private CglibProxy cglibProxy;
    @Autowired
    private CRUDService crudService;
    @Test
    public void test1(){
        CRUD proxy = (CRUD) cglibProxy.proxy(crudService);
        proxy.select();
    }
}

8、Spring AOP

AOP 是 OOP(面向对象编程) 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

  • 在程序运行期间,在不修改源码的情况下对方法进行功能增强
  • 逻辑清晰,开发核心业务的时候,不必关注增强业务的代码
  • 减少重复代码,提高开发效率,便于后期维护

8.1、Aop术语解释

  • Target(目标对象):代理的目标对象
  • Proxy (代理):一个类被 AOP 织入增强后,就产生一个结果代理类
  • Joinpoint(连接点):所谓连接点是指那些可以被拦截到的点。在spring中,这些点指的是方法,因为 spring只支持方法类型的连接点
  • Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义
  • Advice(通知/ 增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知 分类:前置通知、后置通知、异常通知、最终通知、环绕通知
  • Aspect(切面):是切入点和通知(引介)的结合
  • Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring采用动态代理织 入,而AspectJ采用编译期织入和类装载期织入

8.2、Aop快速入门

导入依赖

<dependencies>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!--spring-test-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.9</version>
        <scope>test</scope>
    </dependency>
    <!--aop-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
</dependencies>

service

public interface CRUD {
    void select();
    void insert();
    void update();
    void delete();
}
public class CRUDService implements CRUD {
    public void select() {
        System.out.println("假装自己执行了select");
    }

    public void insert() {
        System.out.println("假装自己执行了insert");
    }

    public void update() {
        System.out.println("假装自己执行了update");
    }

    public void delete() {
        System.out.println("假装自己执行了delete");
    }
}

aop

public class CRUDAdvice {
    public void before(){
        System.out.println("前置通知");
    }
    public void afterReturning(){
        System.out.println("后置通知");
    }
    public void afterThrowing(){
        System.out.println("异常通知");
    }
    public void after(){
        System.out.println("最终通知");
    }
    public void around(ProceedingJoinPoint ProceedingJoinPoint){
        System.out.println("环绕开始");
        try {
            ProceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕结束");
    }
}

applicationContent.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: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/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
    <bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
    <aop:config>
        <aop:aspect ref="crudAdvice">
            <aop:before method="before" pointcut="execution(* cn.winkto.service.CRUDService.*(..))"></aop:before>
            <aop:after method="afterReturning" pointcut="execution(* cn.winkto.service.CRUDService.*(..))"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:applicationContent.xml"})
public class MyTest {
    @Autowired
    private CRUD crud;
    @Test
    public void test(){
        crud.select();
    }
}

8.3、Aop详解

8.3.1、切点表达式
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号 * 代替,代表任意
  • 包名与类名之间一个点 . 代表当前包下的类,两个点 … 表示当前包及其子包下的类
  • 参数列表可以使用两个点 … 表示任意个数,任意类型的参数列表
8.3.2、切点表达式的抽取
<?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: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/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
    <bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
    <aop:config>
        <aop:aspect ref="crudAdvice">
            <aop:pointcut id="point1" expression="execution(* cn.winkto.service.CRUDService.*(..))"/>
            <aop:before method="before" pointcut-ref="point1"></aop:before>
            <aop:after method="afterReturning" pointcut-ref="point1"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>
<?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: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/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="crudService" class="cn.winkto.service.CRUDService"></bean>
    <bean id="crudAdvice" class="cn.winkto.aop.CRUDAdvice"></bean>
    <aop:config>
        <aop:pointcut id="point1" expression="execution(* cn.winkto.service.CRUDService.*(..))"/>
        <aop:aspect ref="crudAdvice">
            <aop:before method="before" pointcut-ref="point1"></aop:before>
            <aop:after method="afterReturning" pointcut-ref="point1"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>
8.3.3、通知类型
<aop:通知类型 method=“通知类中方法名” pointcut=“切点表达式"></aop:通知类型>
名称标签说明
前置通知<aop:before>用于配置前置通知,指定增强的方法在切入点方法之前执行
后置通知<aop:afterReturning>用于配置后置通知。指定增强的方法在切入点方法之后执行
异常通知<aop:afterThrowing>用于配置异常通知。指定增强的方法出现异常后执行
最终通知<aop:after>用于配置最终通知。无论切入点方法执行时是否有异常,都会执行
环绕通知<aop:around>用于配置环绕通知。开发者可以手动控制增强代码在什么时候执行

后置通知与异常通知互斥,环绕通知一般独立使用

9、Spring注解开发(AOP部分)

导入依赖

<dependencies>
    <!--spring-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!--spring-test-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.9</version>
        <scope>test</scope>
    </dependency>
    <!--aop-->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.6</version>
    </dependency>
</dependencies>

service

public interface CRUD {
    void select();
    void insert();
    void update();
    void delete();
}
public class CRUDService implements CRUD {
    public void select() {
        System.out.println("假装自己执行了select");
    }

    public void insert() {
        System.out.println("假装自己执行了insert");
    }

    public void update() {
        System.out.println("假装自己执行了update");
    }

    public void delete() {
        System.out.println("假装自己执行了delete");
    }
}

aop

@Component
//标注为切面类
@Aspect
public class CRUDAdvice {
    @Pointcut("execution(* cn.winkto.service.CRUDService.*(..))")
    public void point(){

    }
    @Before("point()")
    public void before(){
        System.out.println("前置通知");
    }
    @AfterReturning("point()")
    public void afterReturning(){
        System.out.println("后置通知");
    }
    public void afterThrowing(){
        System.out.println("异常通知");
    }
    public void after(){
        System.out.println("最终通知");
    }
    public void around(ProceedingJoinPoint ProceedingJoinPoint){
        System.out.println("环绕开始");
        try {
            ProceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕结束");
    }
}

config

@Configuration
@ComponentScan("cn.winkto")
//开启自动aop代理
@EnableAspectJAutoProxy
public class WinktoConfig {
    @Bean("objectMapper")
    public ObjectMapper getObjectMapper(){
        return new ObjectMapper();
    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
    @Autowired
    private CRUD crud;
    @Test
    public void test(){
        crud.select();
    }
}

10、Spring事务

  • 编程式事务:直接把事务的代码和业务代码耦合到一起,在实际开发中不用(下文不进行详细阐述)
  • 声明式事务:采用配置的方式来实现的事务控制,业务代码与事务代码实现解耦合

10.1、声明式事务(基于XML,整合mybatis)

实体类

public class Person {
    private int pid;
    private String pname;
    private String ppassword;
}

mapper

public interface PersonMapper {
    List<Person> selectPerson();
}
public class PersonMapperImpl implements PersonMapper {
    private SqlSession sqlSession;

    public PersonMapperImpl(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<Person> selectPerson() {
        return sqlSession.getMapper(PersonMapper.class).selectPerson();
    }
}

映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.winkto.mapper.PersonMapper">
    <select id="selectPerson" resultType="Person">
        select * from person
    </select>
</mapper>

数据库配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
user=root
password=blingbling123.

mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <package name="cn.winkto.bean"></package>
    </typeAliases>
    <mappers>
        <package name="cn.winkto.mapper"/>
    </mappers>
</configuration>

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"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       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
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--开启注解扫描-->
    <context:component-scan base-package="cn.winkto" />
    <context:property-placeholder location="classpath:database.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>
    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="mybatis-config.xml" />
    </bean>
    <!--sqlsession-->
    <bean id="sqlsession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    <bean id="personMapper" class="cn.winkto.mapper.PersonMapperImpl">
        <constructor-arg name="sqlSession" ref="sqlsession" />
    </bean>
    <!--事务管理器-->
    <bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg name="dataSource" ref="dataSource" />
    </bean>
    <!--通知增强-->
    <tx:advice id="txAdvice" transaction-manager="tx">
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <!--织入事务-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(* cn.winkto.mapper.PersonMapperImpl.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point" />
    </aop:config>
</beans>

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:applicationContent.xml"})
public class MyTest {
    @Autowired
    private PersonMapper personMapper;
    @Test
    public void test(){
        System.out.println(personMapper.selectPerson());
    }
}
10.1.1、 事务参数的配置详解
<tx:method name="selectPerson" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
  • name:切点方法名称(可以使用*做匹配,类似于模糊查询)
  • isolation:事务的隔离级别
  • propogation:事务的传播行为
  • timeout:超时时间
  • read-only:是否只读

10.2、声明式事务(基于注解,整合mybatis)

实体类

public class Person {
    private int pid;
    private String pname;
    private String ppassword;
}

数据库配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
user=root
password=blingbling123.

mapper

public interface PersonMapper {
    List<Person> selectPerson();
}
@Repository("personMapper")
public class PersonMapperImpl implements PersonMapper {
    @Autowired
    private SqlSessionTemplate sqlSession;

    public PersonMapperImpl(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    //配置事务属性(可放置在类上,k)
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout = -1,readOnly = true)
    public List<Person> selectPerson() {
        return sqlSession.getMapper(PersonMapper.class).selectPerson();
    }
}

映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.winkto.mapper.PersonMapper">
    <select id="selectPerson" resultType="Person">
        select * from person
    </select>
</mapper>

mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <package name="cn.winkto.bean"></package>
    </typeAliases>
    <mappers>
        <package name="cn.winkto.mapper"/>
    </mappers>
</configuration>

config

@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
@ComponentScan("cn.winkto")
@PropertySource("classpath:database.properties")

public class WinktoConfig {
    @Value("${driver}")
    private String driver;
    @Value("${url}")
    private String url;
    @Value("${user}")
    private String user;
    @Value("${password}")
    private String password;

    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(user);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Autowired DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
        return sqlSessionFactoryBean;
    }

    @Bean("sqlSession")
    public SqlSessionTemplate sqlSessionTemplate(@Autowired SqlSessionFactoryBean sqlSessionFactoryBean) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryBean.getObject());
    }

    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }
}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WinktoConfig.class})
public class MyTest {
    @Autowired
    private PersonMapper personMapper;
    @Test
    public void test(){
        System.out.println(personMapper.selectPerson());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

眼眸流转

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值