Spring

DI是IoC的技术实现
DI:依赖注入,(Dependence injection)创建对象是由容器创建,只需要提供对象名即可实现对象的创建。

DI是通过依赖注入给属性赋值。

String使用的DI实现了IOC功能,底层是使用了反射机制。

spring链接:CLICK-HERE


Beans.xml

在这里插入图片描述


测试spring的IoC功能(自动创建对象):

创建maven工程,配置pom文件,使用spring最新版找不到jar包,只好使用spring-5.2.5版本的spring,顺利找到jar,进行下一步的操作。

在这里插入图片描述

spring依赖:

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
  </dependencies>

spring自动创建对象的时机:

在这里插入图片描述
并且会创建所有的对象,并把创建好的对象放到容器的Map集合中储存,以键值对的形式存在,Key为id,Value为new出来的对象。取出对象是依据id取。

取出对象: ac.getBean(id值) 注意这里应该有强制类型转换,具体转换的类型依据取出的对象的类型。


获取容器中对象信息的API

  1. 获取容器中定义的对象的数量:int nums = ac.GetBeanDefinationCount()
  2. 容器中每个对象的名称:String names[] = ac.GetBeanDefinationNames()

创建非自定义的类的对象

例如要创建一个date类型的对象,只需要在beans.xml文件中声明一下即可。

<bean id="myDate" class="java.util.Date"/>

注明全限定名称即可创建。

spring创建对象,默认调用的是无参数构造方法。

DI

  1. DI的语法分类
    在这里插入图片描述

DI的分类

在这里插入图片描述

简单类型的set注入:

在applicationContext.xml配置文件中的bean标签中添加语法:

<?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="myStudent" class="com.tommy.ba01.Student">
        <property name="name" value="张三"/>
        <property name="age" value="16"/>
    </bean>
</beans>

注意,如果要做赋值的类中没有set方法,那么将会报错,无法实现属性的赋值。

引用类型的set注入:

语法代码如下:

<?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="myStudent" class="com.tommy.ba02.Student">
        <property name="name" value="张三"/>
        <property name="school" ref="mySchool"/>
        <property name="age" value="18"/>
    </bean>

    <bean id="mySchool" class="com.tommy.ba02.School">
        <property name="name" value="PKU"/>
        <property name="address" value="BeiJing"/>
    </bean>
</beans>

注意,再给引用类型传值时,不能用value吗,用ref,不然会报错误:NoSuchMethodError


构造注入

spring调用类有参数的构造方法,在创建对象的同时,给Constructor的属性赋值。
构造注入使用<Constructor-arg>标签,一个标签表示一个构造方法中的一个参数

Constructor-arg标签属性:

  1. name:表示构造方法的形参名
  2. index:表示构造方法的参数位置,从左往右依次是:0, 1, 2, ⋯ \cdots
  3. 构造方法的形参类型是简单类型的使用value
  4. 构造方法的形参类型时引用类型的使用ref

构造注入的示例代码:

<?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="myStudent" class="com.tommy.ba03.Student">
        <constructor-arg name="school" ref="mySchool"/>
        <constructor-arg name="age" value="18"/>
        <constructor-arg name="name" value="张三"/>
    </bean>

    <bean id="mySchool" class="com.tommy.ba03.School">
        <property name="name" value="PKU"/>
        <property name="address" value="BeiJing"/>
    </bean>
</beans>

执行步骤:
在这里插入图片描述
(相当于按照标签的个数自动重载了)


引用类型的自动注入

关键字:autowire="byType/byName "
spring框架根据某些规则给引用类型赋值。

使用的规则:

  1. byName(按名称注入):JAVA类中引用类型的属性名spring配置文件(容器) 中的<bean>的id相同且数据类型是一样的,这样可完成引用类型的自动赋值。

bean属性: autowire="byName"

使用实例:

<?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="myStudent" class="com.tommy.ba03.Student" autowire="byName">
        <constructor-arg name="school" ref="school"/>
        <constructor-arg name="age" value="18"/>
        <constructor-arg name="name" value="张三"/>
    </bean>

    <bean id="school" class="com.tommy.ba03.School">
        <property name="name" value="北京职业技术学院"/>
        <property name="address" value="山东菏泽曹县"/>
    </bean>

</beans>

代码关系图解:
在这里插入图片描述

  1. byType(按类型注入):java类中的引用数据类型和spring的<bean>中的引用类型的数据类型时同源关系,这样的可以实现赋值。

同源关系:

  1. java类中的引用数据类型和<bean>中的class的值得的数据类型是一样的。
  2. java类中的引用数据类型和<bean>中的class的数据类型是父子类关系的。
  3. java类中的引用数据类型和<bean>中的class的数据类型是接口和实现类关系的。

在这里插入图片描述
注意:在byType中,在xml配置文件中声明的bean只能有一个符合条件的,多余一个是错误的。

代码实例:
spring-student.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="myStudent" class="com.tommy.ba04.Student" autowire="byType">
        <property name="age" value="18"/>
        <property name="name" value="张三"/>
    </bean>

</beans>

spring-school.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="school" class="com.tommy.ba04.School">
        <property name="name" value="西北工业大学"/>
        <property name="address" value="陕西西安"/>
    </bean>

</beans>

total.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">

    <import resource="classpath:resource04/spring-school.xml"/>
    <import resource="classpath:resource04/spring-student.xml"/>
</beans>

total 的作用是整合配置文件

注解:byName 的注解:执行过程是:在读取ApplicationContext.xml配置文件的autowired="byName"时,到此类中找到引用类型的变量,将此引用类型的名字和配置文件中的bean标签的id值去对比,直到找到相同的讲这个bean标签中的值自动付给引用类型。

byType注解:执行过程:在读取到ApplicationContext.xml中的bean标签中有autowired="byType"时,自动到类中寻找所有的引用类型,读取类型和配置文件中的bean标签中的class进行对比,直到找到类型是同源关系的,spring将进行自动复制。

注解:在使用自动赋值后不用再主bean标签中写入property id="" ref=""了


使用注解

在这里插入图片描述

在这里插入图片描述
注解的使用步骤:
在这里插入图片描述


组件扫描器(component-scan)

basepackage:指定注解在项目中的包名

component-scan工作方式:spring会遍历扫描basepackage指定的包,以及其中的子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。

扫描多个包的三种方式:
在这里插入图片描述

@value:简单类型的属性赋值

语法@value(value = " ") 注意这里的属性值value是String类型的,表示简单类型的属性值

定义的位置:

  1. 在属性定义的上面,不用set方法,推荐使用。
  2. 在set方法的上面。

测试代码:

package com.tommy.ba02;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "myStudent02")
public class Student {

    @Value(value = "张三")
    private String name;
    @Value(value = "99")
    private Integer age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

引用类型的赋值

使用@AutoWired:

默认为byType的匹配模式。

  1. 在属性的上面,不需要set方法
  2. 在set方法的上面

实例源代码:

package com.tommy.ba03;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "myStudent03")
public class Student {

    @Value(value = "张三")
    private String name;

    @Value(value = "99")
    private Integer age;

    @Autowired
    private School school;


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}

package com.tommy.ba03;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//注意这里的mySchool代表的就是使用bean标签时的id值
@Component(value = "mySchool")

//这样容器中就有了school类型的数据了。
//按类型自动注入就会自动在容器中匹配这个School类型
public class School {

    @Value(value = "北京")
    private String address;

    @Value(value = "北大清华")
    private String name;

    public void setAddress(String address) {
        this.address = address;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "School{" +
                "address='" + address + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

在配置文件中使用bean标签实现的功能一模一样。

<?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"
       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="com.tommy.ba03" />

//这样在容器中一样创建了school对象。和使用注解的方式一样。
    <bean id="mySchool" class="com.tommy.ba03.School">
        <property name="name" value="TsingHuaUniversity"/>
        <property name="address" value="BeiJing"/>
    </bean>
</beans>

byName:

  1. 在属性上面加入@Autowired
  2. 在后面加上@Qualifier(value=“bean的id”)

示例代码:

package com.tommy.ba04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "myStudent04")
public class Student {

    @Value(value = "张三")
    private String name;

    @Value(value = "99")
    private Integer age;

    @Autowired
    @Qualifier(value = "mySchool") //这两个注解没有先后顺序。
    private School school;


    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", school=" + school +
                '}';
    }
}

探讨@Autowire的属性required:

required, 是一个boolean类型的,默认值为true
required = true:表示引用类型的赋值失败,程序报错,并终止执行。
required = false:引用类型如果赋值失败,程序正常执行,引用类型的 结果赋值为null
使用时最好使用true,避免空指针异常,便于程序的调试。

@resource

来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用他给引用类型赋值,使用的也是自动注入原理,支持byName, byType, 默认是byName

使用位置:

  1. 在属性定义的上面,无需使用set方法,推荐使用
  2. 在set方法的上面

原则是默认为byName的方式,该方式赋值失败后,在使用byType的复制方式。

如果只想使用byName的赋值方式,如下图:

问题:一使用@Resource注解就报错,该导入的javax依赖也已经导入了,就是一直报错,心态崩了。

"C:\Program Files\Java\jdk-16.0.1\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.2\lib\idea_rt.jar=64921:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.2\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.2\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.2\plugins\junit\lib\junit-rt.jar;C:\Users\TOMMY\IdeaProjects\untitled3\target\test-classes;C:\Users\TOMMY\IdeaProjects\untitled3\target\classes;C:\Users\TOMMY\.m2\repository\org\apache\wicket\wicket\1.3.2\wicket-1.3.2.jar;C:\Users\TOMMY\.m2\repository\org\slf4j\slf4j-api\1.4.2\slf4j-api-1.4.2.jar;C:\Users\TOMMY\.m2\repository\org\slf4j\slf4j-log4j12\1.4.2\slf4j-log4j12-1.4.2.jar;C:\Users\TOMMY\.m2\repository\log4j\log4j\1.2.14\log4j-1.2.14.jar;C:\Users\TOMMY\.m2\repository\junit\junit\4.13\junit-4.13.jar;C:\Users\TOMMY\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\TOMMY\.m2\repository\org\mortbay\jetty\jetty\6.1.4\jetty-6.1.4.jar;C:\Users\TOMMY\.m2\repository\org\mortbay\jetty\servlet-api-2.5\6.1.4\servlet-api-2.5-6.1.4.jar;C:\Users\TOMMY\.m2\repository\org\mortbay\jetty\jetty-util\6.1.4\jetty-util-6.1.4.jar;C:\Users\TOMMY\.m2\repository\org\mortbay\jetty\jetty-management\6.1.4\jetty-management-6.1.4.jar;C:\Users\TOMMY\.m2\repository\mx4j\mx4j\3.0.1\mx4j-3.0.1.jar;C:\Users\TOMMY\.m2\repository\mx4j\mx4j-tools\3.0.1\mx4j-tools-3.0.1.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-context\5.2.5.RELEASE\spring-context-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-aop\5.2.5.RELEASE\spring-aop-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-beans\5.2.5.RELEASE\spring-beans-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-core\5.2.5.RELEASE\spring-core-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-jcl\5.2.5.RELEASE\spring-jcl-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\org\springframework\spring-expression\5.2.5.RELEASE\spring-expression-5.2.5.RELEASE.jar;C:\Users\TOMMY\.m2\repository\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 com.tommy.MyTest03,test03

org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [applicationContext.xml]; nested exception is java.lang.NoSuchMethodError: 'void org.slf4j.spi.LocationAwareLogger.log(org.slf4j.Marker, java.lang.String, int, java.lang.String, java.lang.Object[], java.lang.Throwable)'

	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:415)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:305)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:224)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:195)
	at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:257)
	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:128)
	at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:94)
	at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:133)
	at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:637)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
	at com.tommy.MyTest03.test03(MyTest03.java:14)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.NoSuchMethodError: 'void org.slf4j.spi.LocationAwareLogger.log(org.slf4j.Marker, java.lang.String, int, java.lang.String, java.lang.Object[], java.lang.Throwable)'
	at org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog.trace(LogAdapter.java:482)
	at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.registerDefaultFilters(ClassPathScanningCandidateComponentProvider.java:211)
	at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.<init>(ClassPathBeanDefinitionScanner.java:166)
	at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.createScanner(ComponentScanBeanDefinitionParser.java:132)
	at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.configureScanner(ComponentScanBeanDefinitionParser.java:103)
	at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:89)
	at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:74)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1391)
	at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1371)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:179)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:149)
	at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:96)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:509)
	at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:389)
	... 39 more


Process finished with exit code -1

这报错服了。。。。

注解:如果在项目中属性的值需频繁的修改,建议使用xml配置文件的形式赋值,改动小用注解赋值。


动态代理

可以在程序执行的过程中创建代理对象,通过代理对象执行方法给目标类的方法增加额外的功能。

实现步骤:

  1. 创建目标类
  2. 创建InvocationHandler接口的实现类,在这个类中实现给目标方法增加功能。
  3. 使用jdk中的类proxy创建代理对象,实现创建对象的能力。

代码实例:

package com.tommy.handler;

import com.tommy.util.ServiceTools;

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

public class MyIncationHandler implements InvocationHandler {

    private Object target;

    public MyIncationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object res = null;
        ServiceTools.date();
        res = method.invoke(target, args); // 代表的是SomeServiceImpl中的方法doSome()或者doOther()
        ServiceTools.submit();
        return res;
    }
}

可以在动态代理模块中实现方法的执行选择等逻辑算法的实现,而在不表方法中的代码并不需要进行任何修改,这样最大限度的实现了解耦合。便于代码的分布式管理。

在这里插入图片描述


AOP

动态代理的范式形式,规范化的动态代理机制。面向切面编程

实现方式:

  1. jdk动态代理:使用jdk中的proxy, method, InvocationHandler创建代理对象,jdk动态代理要求目标类必须实现接口。
  2. cglib动态代理:第三方的工具库,创建代理对象,原理是继承,通过继承目标类创建子类,子类就是代理对象,要求目标类不能是final的,方法也不能是final的。
    在这里插入图片描述

使用的AOP:开源AOP框架aspectJ
spring框架集成了aspectJ框架,可实现通过spring直接使用aspectJ的功能。

aspectJ实现aop功能的两种方式:

  1. 使用xml配置文件
  2. 使用注解(5个)

切入点表达式:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
注解
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
? 表示可选内容

使用通配符:

通配符

execution(public * *(..))
指定切入点为:任意公共方法。

execution(* set*(..))
指定切入点为:任何一个以“set”开始的方法。

execution(* com.xyz.service.*.*(..))
指定切入点为:定义在 service 包里的任意类的任意方法。

execution(* com.xyz.service..*.*(..))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“ ∗ * ”,表示包、子包下的所有类。

execution(* *..service.*.*(..))
指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点

添加依赖:

<!-- spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>

<!-- aspectJ依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>

在这里插入图片描述

使用AOP实现一个前置通知:

  1. 添加maven依赖:
<!-- spring依赖 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.2.5.RELEASE</version>
		</dependency>
<!-- aspectJ dependency -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>5.2.5.RELEASE</version>
		</dependency>
  1. 创建目标类,创建接口和他的实现类。
    目标:在不改动源代码的基础上为方法增加功能。

  2. 创建切面类:在类的上面加上@aspect,再类中定义方法,这个方法就是切面要执行的功能代码,要在功能方法上面加上通知注解:例如@Before等通知注解。并且指定切入点表达式execution

  3. 创建spring的配置文件applicationContext.xml,声明对象,把对象交给容器统一管理
    1)生成目标对象
    2)生成切面类对象
    3)自动代理生成器,用于完成代理对象的自动创建。

  4. 最后创建测试类进行从容器中获取对象进行代码测试即可。

指定通知方法中的参数:

JoinPoint:
可以在通知方法中获取方法执行时的信息,参数JoinPoint的值由框架赋予,必须是第一个位置的参数。

@Before(value = "execution(public void com.bjpowernode.ba01.SomeServiceImpl.doSome(String, Integer))")
    public void myBefore(JoinPoint jp) {
        System.out.println(jp.getSignature());
        Object args [] = jp.getArgs();
        for(Object arg : args) {
			System.out.println("参数 = " + arg);
		}
        System.out.println(jp.getSignature().getName());
        System.out.println("前置通知:在目标方法执行之前输出时间: " + new Date());
    }

注意:获取参数的方法的返回值为Object类型的数组:Object[] getArgs();


后置通知:

后置通知在切面类的上面加上@AfterReturning(value="execution(...)", returning="res"),res要和切面方法的参数变量名一样才行,用处是获取到目标方法的返回值,可以拿到返回值,根据返回值做业务方法。

@AfterReturning(value = "execution(String com.tommy.ba02.SomeServiceImpl.myStudent(String, Integer))",
            returning = "res1")
    public void myAfterReturning(Object res1) {
        System.out.println("这是后置通知");
    }

切面方法的定义要求:

  1. public
  2. 方法没有返回值
  3. 方法名自定义
  4. 方法有参数:
    推荐使用Object,参数名自定义

后置通知@Afterreturning有两个属性:

  1. value,切入点表达式
    2.returning表示自定义的变量 ,表示目标方法的返回值的,自定义的变量名必须和通知方法的形参名一样

环绕通知

功能最强大的通知
环绕通知方法的定义格式:

  1. public
  2. 必须有一个返回值,推荐用Object
  3. 方法名称自定义
  4. 方法有参数,固定的参数 ProceedingJoinPoint

Pointcut注解:

定义和管理切入点,如果你的项目中有多个切入点表达式是重复的,可以复用的,可以使用@PointCut
属性:切入点表达式
位置:在自定义方法的上面

当使用此注解在一个方法的上面时,此时这个方法的名称就是切入点表达式的别名,其他通知中,value属性就可以使用这个方法名称,代替切入点表达式了。

自定义的方法中不需要代码。

一般定义为私有的。

如果目标方法没有接口,那么默认使用的是CGLIB动态代理。


有接口也能用CGLIB动态代理

如果你期望目标类有接口,使用cglib动态代理,在配置文件中加入:

<aop:aspectj-autoproxy proxy-target-class="true" />

MyBatis和Spring的集成使用:

原理是使用了spring 的ioc功能。

用的技术是:ioc 。
为什么ioc:能把mybatis和spring集成在一起,像一个框架, 是因为ioc能创建对象。
可以把mybatis框架中的对象交给spring统一创建, 开发人员从spring中获取对象。
开发人员就不用同时面对两个或多个框架了, 就面对一个spring

mybatis使用步骤,对象
1.定义dao接口 ,StudentDao
2.定义mapper文件 StudentDao.xml
3.定义mybatis的主配置文件 mybatis.xml
4.创建dao的代理对象, StudentDao dao = SqlSession.getMapper(StudentDao.class);

List students = dao.selectStudents();

要使用dao对象,需要使用getMapper()方法,
怎么能使用getMapper()方法,需要哪些条件
1.获取SqlSession对象, 需要使用SqlSessionFactory的openSession()方法。
2.创建SqlSessionFactory对象。 通过读取mybatis的主配置文件,能创建SqlSessionFactory对象

需要SqlSessionFactory对象, 使用Factory能获取SqlSession ,有了SqlSession就能有dao , 目的就是获取dao对象
Factory创建需要读取主配置文件

我们会使用独立的连接池类替换mybatis默认自己带的, 把连接池类也交给spring创建。

主配置文件:
1.数据库信息

<environment id="mydev">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <!--数据库的驱动类名-->
               <property name="driver" value="com.mysql.jdbc.Driver"/>
               <!--连接数据库的url字符串-->
               <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
               <!--访问数据库的用户名-->
               <property name="username" value="root"/>
               <!--密码-->
               <property name="password" value="123456"/>
           </dataSource>
  1. mapper文件的位置
   <mappers>
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
    </mappers>

通过以上的说明,我们需要让spring创建以下对象
1.独立的连接池类的对象, 使用阿里的druid连接池
2.SqlSessionFactory对象
3.创建出dao对象

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值