spring:分层的JavaSE/EE应用full-stack轻量级开源框架,以Ioc(反转控制)和AOP(面相切面编程)为内核,提供了展现层springMVC和持久层spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的JavaEE企业应用开源框架。
优势:
1、方便解耦,简化开发
2、AOP编程的支持
3、声明式事务的支持
4、方便程序的测试
5、方便集成各种优秀框架
6、降低JavaEE的使用难度
7、源码的经典的学习范例
程序的耦合:程序键的依赖关系,包括类之间的依赖,方法间的依赖。
解耦:降低程序间的依赖关系
实际开发中应该做到,编译期不依赖,运行时才依赖
解决思路:
第一步:使用反射来创建对象,而避免使用new关键字
第二步:通过读取配置文件来获取要创建的对象全限定类名。
Ioc:
概念:控制反转,把创建对象的权利交给框架,是框架的重要特征,并非面向对象的专用术语。它包括依赖注入和依赖查找。
作用:削减计算机程序的耦合,解除我们代码中的依赖关系。
使用:
1、配置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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao" class="lianbang.wu.dao.Impl.AccountDaoImpl"></bean>
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl"></bean>
</beans>
2、获取ioc核心容器,并且根据id获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("Bean.xml");
IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);
IAccountService accountService = ac.getBean("accountService",IAccountService.class);
ApplicationContext的三个常用实现类:
1、ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下,不在的话,加载不了
2、FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件,前提是有访问权限
3、AnnotationConfigApplicationContext:它是用于读取注解创建容器的。
ApplicationContext:它在构建核心容器时,创建对象采用的策略是采用立即加载的方式,也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象,适用单例对象
BeanFactory:它在构建核心容器时,创建对象采用的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象,适用多例对象
创建Bean的三种方式:
第一种:使用默认构造函数创建
<bean id="accountDao" class="lianbang.wu.dao.Impl.AccountDaoImpl"></bean>
注意:如果类中没有默认构造函数,则对象无法创建
第二种:使用普通工厂类中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
<bean id="instanceFactory" class="lianbang.wu.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
第三种:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id="accountService" class="lianbang.wu.factory.StaticFactory" factory-method="getAccountService"></bean>
Bean的作用范围调整:
bean标签的scope属性
作用:用于指定bean的作用范围
取值:
singleton:单例,默认值
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围,当不是集群时,它就是session
<bean id="product" class="lianbang.wu.domain.Product" scope="singleton"></bean>
Bean的生命周期
单例对象
出生:当容器创建时,对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
多例对象
出生:当我们使用对象时,创建
活着:对象只要在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,有java的垃圾回收器回收
spring的依赖注入:
作用:维护依赖关系
能注入的数据:
1、基本类型和String
2、其他bean类型(在配置文件中或者注解配置过的bean)
3、复杂类型/集合类型
注入的方式:
1、使用构造函数提供
在bean标签的内部,使用标签constructor-arg
标签中的属性:
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置从0开始
name:用于指定给构造函数中指定名称的参数赋值
value:用于提供基本类型和string类型的数据
ref:用于指定其他bean类型数据,它指的就是在spring的Ioc核心容器中出现过的bean对象
</bean>
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl">
<constructor-arg name="name" value="读者"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" value="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>
好处:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
坏处:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据也必须提供。
2、使用set方法提供
在bean标签的内部,使用property
标签的属性:
name:用于指定注入时所调用的set方法名称
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc容器中出现过的bean对象
</bean>
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl">
<property name="name" value="读者"></property>
<property name="age" value="18"></property>
<property name="birthday" value="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>
好处:创建对象时没有明确的限制,可以直接使用默认构造函数
坏处:如果有某个成员必须有值,则获取对象是有可能set方法没有执行
3、使用注解提供
复杂类型注入(集合,数组,propertise)
1、array,list,set
</bean>
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl">
<property name="name">
<array>aaa</array>
<array>bbb</array>
<array>ccc</array>
</property>
</bean>
注意:只需将property标签下对应的子标签改变成对应的类型
2、map
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl">
<property name="name">
<map>
<entry key="读者1" value="作品1"></entry>
<entry key="读者2" value="作品2"></entry>
</map>
</property>
</bean>
3、properties
<bean id="accountService" class="lianbang.wu.service.Impl.AccountServiceImpl">
<property name="name">
<props>
<prop key="读者1">作品1</prop>
</props>
</property>
</bean>
常见的Ioc注解:
注意,使用注解配置时,先要修改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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="lianbang.wu"></context:component-scan>
</beans>
1、用于创建对象的:作用就和xml配置文件中bean标签实现的功能一样
@Component
作用:把当前类对象存入spring容器中
属性:value:用于指定bean的id,当我们不写时,默认值是当前类名,首字母小写
@Controller:一般用在表现层
@Service:一般用在业务层
@Repository:一般用在持久层
以上三个注解他们的作用和属性于Conponent是一样的,只是为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。
2、用于注入数据的:作用就和xml配置文件中property标签实现的功能一样
@Autowired
作用;自动按照类型注入,只要容器中有唯一一个bean对象类型和要注入的变量类型匹配,就可以注入成功。如果Ioc容器中没有任何bean类型和要注入的变量类型匹配,则报错,如果Ioc容器中有多个类型匹配,根据变量名称再去匹配Ioc容器中对应类型的Id名称
出现位置:可以在变量上,也可以是方法上
细节:在使用注解注入时,set方法就不是必须的了
@Qualifier
作用:按照类中注入的基础上再按照名称注入,它在给类成员注入时不能单独使用必须与Autowired配合使用,但是在给方法参数注入时可以
属性:value:用于指定注入bean的id。
@Resource
作用:直接按照bean的id注入,它可以单独使用
属性:name:用于指定bean的id
@value
作用:用于注入基本数据类型和String类型的数据
属性:value:用于指定数据的值,它可以使用spring中时spEl
spEl的写法:#{表达式}
3、用于改变作用范围:作用就和在bean标签中使用scope属性实现的功能一样
@Scope
作用:用于指定bean的作用范围
属性:value:指定范围的取值。常用:singleton(默认),prototype
4、和生命周期相关:作用就和bean标准中使用init-method和destroy-method的作用一样
@PreDestroy
作用:用于指定销毁方法
@PostConstruct
作用:用于指定初始化方法
Ioc的其他注解:
@Configuration
作用:当前类是一个配置类
@ConponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包
属性:value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
@Bean
作用:用于把当前方法的返回值作为bean对象,存入spring的ioc容器中
属性:name:用于指定Bean的id,默认值是当前方法的名称
注意:当使用注解配置方法,如果方法有参数,spring框架会去容器中查找有没有可用bean对象,和Autowired机制一样。
使用注解配置类:
ApplicationContext ac = new AnnotationConfigApplicationContext(springConfig.class);
@import
作用:用于导入其他配置类
@propertySource
作用:用于指定properties文件的位置
属性:value,指定文件的名称和路径,classpath,表示类路径下
Spring整合Junit
第一步:导入spring整合Junit的jar包
第二步:使用Junit提供的一个注解把原有的main方法替换成spring提供的
@Runwith
第三步:告知spring的运行器,spring的ioc创建是基于xml还是注解的,并且说明位置
@ContextConfiguration
location:指定xml文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在的位置
注意:当我们使用spring 5.X版本的时候,要求Junit的jar必须是4.12以上
AOP:
概念:面向切面编程,它就是把完美程序重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对完美的已有方法进行增强。
相关术语:
Joinpoint:连接点:简单的说就是可以被增强的方法
Pointcut:切入点:简单的说就是被增强了的方法
Advice:通知:拦截到joinpoint之后所要做的事情,通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction:引介:是一种特殊的通知,在不修改代码的前提下,可以在运行期为类动态的添加一些方法。
Target:目标对象:被代理对象
Weaving:把增强应用到目标对象来创建新的代理对象的过程
Proxy:代理:一个类被AOP织入增强后,就产生一个结果代理类
Aspect:切面:切入点和通知的结合
基于XML方式:
1、把切面添加到Ioc容器
<bean id="logger" class="lianbang.wu.utils.Logger"></bean>
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id:给切面提供一个唯一标识
ref:是指定通知类bean的id
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
aop:before:表示配置前置通知,在切入点方法执行之前执行
method:指定logger类中哪个方法是前置通知
pointcut:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:execution(表达式)
表达式:访问修饰符 返回值 包名.类名.方法名(参数列表)
全通配写法 * *..*.*(..)
实际开发通常写法:* 包名.*.*(..)
aop:after-returning:后置通知,在切入点方法执行之后执行
aop:after-throwing:异常通知,在切入点执行产生异常之后执行
aop:after:最终通知,无论切入点方法是否正常执行,它都会在后面执行
aop:around:环绕配置,当配置环绕通知之后,需要在切入点方法中传入参数,明确调用切入点等等
<aop:config>
<aop:aspect id="logAdvice" ref="logger">
<aop:before method="printLog" pointcut="execution(public void lianbang.wu.service.Impl.AccountServiceImpl.saveAccount())"></aop:before>
</aop:aspect>
</aop:config>
</beans>
基于注解方式:
@Component("logger")
@Aspect
//@EnableAspectJAutoProxy
public class Logger {
@Pointcut("execution(* lianbang.wu.service.Impl.*.*(..))")
private void pt1(){};
@Before("pt1()")
public void printLog(){
System.out.println("Logger类中的方法开始记录日志。。。");
}
注意:环绕通知必须传入ProceedingJoinPoint类型参数
@Around("pt1()")
public void around(ProceedingJoinPoint joinPoint){
System.out.println("前置通知");
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("后置通知");
}
jdbcTemplate
作用:用于和数据库交互,实现对表的CRUD操作
public class JdbcTemplateDemo {
public static void main(String[] args) {
//0、准备数据源
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/eesy");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("120609");
//1、创建对象
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(driverManagerDataSource);
//2、执行操作
jdbcTemplate.execute("insert into account(id,uid,money)value (5,46,1000)");
}
}
补充:可以将上面2个new出来的对象放入Ioc对象,在进行调用