====================================================================
0612:
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="test.student">
<property name="name" value="douguangyao"/>
<property name="age" value="20"/>
</bean>
</beans>
spring的对象获取
public void test1(){
ApplicationContext acx = new ClassPathXmlApplicationContext("spring.xml");
student student = (test.student) acx.getBean("student");
System.out.println(student);
}
加载spring容器的三种方法:
1. 类路径获得配置文件:
public void test1(){
ApplicationContext acx = new ClassPathXmlApplicationContext("spring.xml");
student student = (test.student) acx.getBean("student");
System.out.println(student);
}
2. 文件系统路径获得配置文件
public void test2(){
ApplicationContext acx = new FileSystemXmlApplicationContext("D:\\workplace\\ideaworkplace\\springStudy\\src\\main\\resources\\spring.xml");
student student = (test.student) acx.getBean("student");
System.out.println(student);
}
3. 使用BeanFactory
public void test3(){
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("D:\\workplace\\ideaworkplace\\springStudy\\src\\main\\resources\\spring.xml"));
student student = (test.student) beanFactory.getBean("student");
System.out.println(student);
}
BeanFactory 采用延迟加载, 在第一次getBean时才会初始化Bean
ApplicationContext 及时加载,在加载容器时就初始化Bean
==================================================================================================================================================
0621:
装配Bean的三种方式
- 采用默认构造函数,在spring的配置文件中使用bean标签, 配以id和属性class之后,且没有其他属性和标签时,采用的就是默认构造函数创建bean对象,
此时如果类中没有默认构造函数,则对象无法创建
<bean id="user" class="dgy.bean.User"></bean>
- 使用某个类中的方法创建对象,并存入spring容器中
<bean id="Factory" class="dgy.bean.UserFactory"></bean>
<bean id="user" factory-bean="Factory" factory-method="getUser"></bean>
注意:工厂中的方法是未被static修饰的
- 使用某个工厂中的静态方法创建对象,并存入对象中
<bean id="usu" class="dgy.bean.UserFactory" factory-method="getUser"></bean>
bean的作用范围调整
bean标签的scope属性,作用:用于指定bean的作用范围
取值:
①:singleton: 单例的(默认)
②:prototype: 多例的
③:request: 作用于web应用的请求范围
④:session: 作用于web应用的会话范围
⑤:global-session: 作用于集群环境的会话范围(全局会话范围),若不是集群环境他就是session
bean对象的生命周期
单例对象:
出生:当容器创建时对象出生
活着:只要容器还在,对象就只要活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象:
出生:但我们使用多例对象时,spring为我们创建对象
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,有java垃圾回收器回收
依赖注入
依赖关系的管理:以后都交给spring来维护,在当前类需要用到其他类的对象时,有spring为我们提供,我们只需要在配置文件中
说明依赖关系的维护。就称之为依赖的注入
依赖注入的数据类型:
基本类型和String
其他bean类型(在配置文件或者注解配置过的bean)
复杂类型(集合类型)
注入的方式:
①:使用构造函数提供
②:使用set方法提供
③:使用注解提供
①构造函数注入(无get/set方法):
使用的标签constructor-arg
标签出现的位置:bean标签内部
标签中的属性
type:用于指定要注入的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据在构造函数中指定索引位置的参数赋值,从0开始
name:用于指定给构造函数中指定名称的参数赋值
value: 用于提供基本类型和String类型的数据
ref: 用于指定其他的bean类型数据,它指的就是在spring的IOC核心容器中出现的bean对象
优势:在获取对象时,注入数据是必须的操作,否则无法创建成功
弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供
<bean id="person" class="dgy.bean.Person">
<constructor-arg name="name" value="dou"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg> //<constructor-arg index="1" value="20"></constructor-arg>
<constructor-arg name="birthday" ref="date"></constructor-arg>
</bean>
<bean id="date" class="java.util.Date"></bean>
②set方法注入(常用方式)
涉及的标签:property
出现的位置:bean标签的内部
标签的属性:
name:用于指定注入时所调用的set方法名称
value:用于指定提供基本数据类型和String的数据
ref: 用于指定其他的bean类型数据,指的是在spring的IOC容器中出现的bean对象
优势:创建对象时没有明确的限制,可以直接使用默认构造函数
弊端:如果有某个成员必须有值,则获取对象时有可能set方法没有执行
<bean id="person" class="dgy.bean.Person">
<property name="age" value="51"></property>
<property name="name" value="douguang"></property>
<property name="birthday" ref="birthday"></property>
</bean>
<bean id="birthday" class="java.util.Date"></bean>
集合数据类型的注入
①:用于给List结构集合注入的标签:list、array、set
②:用于Map结构集合注入的标签: map、props
注意: 结构相同,标签可以互换
<bean id="jcf" class="dgy.bean.JCFtest">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>GGG</value>
<value>JJJ</value>
<value>FFF</value>
</list>
</property>
<property name="myMap">
<map>
<entry key="444" value="DDD"></entry>
<entry key="555" value="EEE"></entry>
</map>
</property>
<property name="myProperties">
<props>
<prop key="1">pr1</prop>
<prop key="2">pr2</prop>
<prop key="3">pr3</prop>
</props>
</property>
</bean>
====================================================================================================================
0624
注解方式:
1. 用于创建对象的:(他们的作用和xml中标签实现的功能是一样的)
①:Component
作用:用于把当前对存入spring容器中
属性:
value:用于指定bean的id,当不写时,默认是当前类名首字母小写
②:Controller:一般用于表现层
③:Service:一般用于业务层
④:Repository:一般用于持久层
总结:以上三个注解他们的作用和属性与Component时一模一样的,他们三个时spring
框架为我们提供的三层使用的注解,使我们三层对象更加清晰
2. 用于注入数据的:(他们的作用和xml中bean中的的标签的作用是一样的)
①:Autowired:
作用:自动按照类型注入,
只要容器中有唯一一个bean对象类型和注入的变量类型匹配,就可以注入成功
如果IOC容器中没用任何bean的类型和要注入的变量类型匹配时,则报错
如果IOC容器中有多个类型匹配时:首先按照类型圈定出来要匹配的对象,然后使用变量名称作为bean的id
在圈定的方位内继续查找,如果对象的id和他的变量名称一样就查找成功,否则报错
出现的位置:变量、方法
细节:在使用注解注入时,set方法就不是必须的了
②:Qualifier:
作用:在按照类型注入的基础上再按照名称注入,它在给类成员注入时,不能单独使用,但是在给方法参数注入时可以
属性:value:用于指定注入bean的id
③:Resource:
作用:直接按照bean的id注入,他可以独立使用
属性:name:用于指定bean的id
总结:以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现
另外集合数据类型只能用xml来实现注入
value:
作用:用于注入基本类型和String类型的数据
属性:value:用于指定数据的值,它可以使用spring中SpEL(Spring的el表达式)
spel的写法:${表达式}
3. 用于改变作用范围的:(他们的作用和xml中bean标签中使用scope属性实现的功能是一样的)
①:Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值,常用取值:singleton、prototype
4. 和生命周期相关的:(他们的作用和xml中bean标签中使用init-method和destroy-method的作用是一样的)
①:PreDestroy
作用:用于指定销毁方法(单例对象,多例对象有垃圾回收器负责)
②:PostConstruct
作用:用于指定初始化方法
XML的约束(两种)
注解的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"
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">
<context:component-scan base-package="com.dgy"></context:component-scan>
</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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
===================================================================================================
0625
spring的新注解
ComponentScan:
作用:用于通过注解指定spring在创建容器时要扫描的包
属性:value和basePackages,两个作用一样,都是用于指定创建容器时要扫描的包
如同xml中的
<context:component-scan base-package="com.dgy"></context:component-scan>
Configuration:声明这个类是配置类 细节:当配置类作为AnnotationConfigApplicationContext的参数是可以不写
Bean:
作用:用于把当前方法的返回值作为bean对象存入spring的IOC容器中
属性:name:用于指定bean的id,当不写时,默认值时当前方法的名称
细节:当我们使用注解配置方法时,如果方法有多个参数,spring框架会去容器中查找用没有可用的bean对象
查找方式和Autowried注解的查找方式一样
import:作用:用于导入其他的配置类
属性:value用于指定其他配置类的字节码,当我们使用import注解后,有import注解的配置类就是主配置类
PropertySource:
作用:用于指定properties文件的位置
属性:value:用于指定文件的名称和路径
关键字:classpath,表示类路径下
====================================================================
Spring整合Junit
首先要导入依赖(要特别注意版本信息)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
/**
* 使用Junit单元测试:测试我们的配置
* Spring整合junit的配置
* 1、导入spring整合junit的jar(坐标)
* 2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
* @Runwith
* 3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
* @ContextConfiguration
* locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
* classes:指定注解类所在地位置
*
* 当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {
@Autowired
private IAccountService as = null;
@Test
public void testFindAll() {
//3.执行方法
List<Account> accounts = as.findAllAccount();
for(Account account : accounts){
System.out.println(account);
}
}
}
=====================================================================================================================================================
0626
AOP(面向切面编程)
它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强
作用:
在程序运行期间,不修改源码对已有方法进行增强。
优势:
减少重复代码
提高开发效率
维护方便
**AOP相关术语**
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
Target(目标对象):代理的目标对象。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。
Aspect(切面):是切入点和通知(引介)的结合
实现方式:
使用动态代理技术
/**
* 动态代理:
* 特点:字节码随用随创建,随用随加载
* 作用:不修改源码的基础上对方法增强
* 分类:
* 基于接口的动态代理
* 基于子类的动态代理
* 基于子类的动态代理:
* 涉及的类:Enhancer
* 提供者:第三方cglib库
* 如何创建代理对象:
* 使用Enhancer类中的create方法
* 创建代理对象的要求:
* 被代理类不能是最终类
* create方法的参数:
* Class:字节码
* 它是用于指定被代理对象的字节码。
*
* Callback:用于提供增强的代码
* 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
* 此接口的实现类都是谁用谁写。
* 我们一般写的都是该接口的子接口实现类:MethodInterceptor
*
*
spring中基于XML的AOP配置步骤
1、把通知Bean也交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!-- 配置Logger类 -->
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!-- 配置切入点表达式 id属性用于指定表达式的唯一标识。expression属性用于指定表达式内容
此标签写在aop:aspect标签内部只能当前切面使用。
它还可以写在aop:aspect外面,此时就变成了所有切面可用
-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置前置通知:在切入点方法执行之前执行
<aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before>-->
<!-- 配置后置通知:在切入点方法正常执行之后值。它和异常通知永远只能执行一个
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>-->
<!-- 配置异常通知:在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing>-->
<!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行
<aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after>-->
<!-- 配置环绕通知 spring中的环绕通知:
它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。-->
<aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
</beans>
还有很多不足之处