Spring概述以及IOC介绍
Spring是什么:
Spring是分层的 Java SE/EE应用 full-stack(全栈式) 轻量级开源框架
提供了表现层 SpringMVC和持久层 Spring JDBC Template以及 业务层 事务管理等众多的企业级应用技术
还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架
两大核心:以 IOC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核
对方法增强,实际上就是使用了动态代理,动态代理也使用了一些反射操作,但单纯使用反射,是很难做出动态代理的
反射的操作:一般我们是可以通过反射,获得对应的类的构成,操作类的信息
动态代理:代理类里面有具体实现类的变量,当我们需要操作实现类时,通过代理类来进行对应实现
那么就会发现,我们执行了代理类的方法,实际上也执行了实现类的方法(操作了对应变量)
且代理类的对应方法可以进行扩展增强(使得实现类操作时,出现了其他操作),这就是静态代理
而动态代理需要一些反射来进行,所以说反射的出现,使得很多框架的出现,甚至可以通过反射,自己写出框架
代理其实也类似于回调模式,只是有以下区别
代理模式需要创建接口实现类,并放入代理类中,隔离性更好,扩展性好
回调函数不需要创建接口实现类,编写方便
Spring发展历程:
一般对于数据库来说,我们设置的参数后,帮我们进行连接操作的是对于驱动的实现类,那么就说明以下耦合度的操作
package com. lagou. test ;
import org. junit. Test ;
import java. sql. * ;
public class JDBCTest {
@Test
public void test1 ( ) throws SQLException , ClassNotFoundException {
Class . forName ( "com.mysql.jdbc.Driver" ) ;
Connection connection =
DriverManager . getConnection ( "jdbc:mysql:///mybatis_db" , "root" , "123456" ) ;
String sql = "select * from user" ;
PreparedStatement preparedStatement = connection. prepareStatement ( sql) ;
ResultSet resultSet = preparedStatement. executeQuery ( ) ;
while ( resultSet. next ( ) ) {
System . out. println ( resultSet. getString ( "username" ) ) ;
}
resultSet. close ( ) ;
preparedStatement. close ( ) ;
connection. close ( ) ;
}
}
这是一个经典的说明,当然也有其他说明,如下
public class a {
public void fa ( ) {
System . out. println ( "a类的执行" ) ;
}
}
public class b {
public a a;
public b ( a a) {
this . a = a;
}
}
public class c {
public static void main ( String [ ] args) {
b b = new b ( new a ( ) ) ;
b. a. fa ( ) ;
}
}
可以发现,b类和a类也是有一定联系的,a类的改变,那么b类的a类变量也会进行改变
当然,也有接口之间的耦合
比如:设计模式的隔离原则,一般的一个接口中,定义了对应接口方法,但这些接口方法,归属不同,如狗和鸟
一个奔跑一个飞行,那么就需要将这个大接口,变成对应的小接口,否则,可以发现大接口中的其他接口
别人实现时,也是可以调用的(明显从意义上不能够调用),这就是一个联系
那么从这些例子,就知道:
耦合:可以理解为程序之间的一种联系
解耦:降低这些联系(要想完全不联系,基本不可以,比如代码和二进制之间,必须有联系)
虽然降低联系,但具体的功能基本也是不变的
框架(依赖)可以说成是封装好的一些程序(变量,方法等等)
Spring优势:
图解:
Spring体系结构:
初识IOC:
概述:
控制反转(Inverse Of Control)不是什么技术,而是一种设计思想,它的目的是指导我们设计出更加松耦合的程序
控制:在java中指的是对象的控制权限(创建、销毁)
反转:指的是对象控制权由原来 由开发者在类中手动控制 反转到 由Spring容器控制(即对象的创建由Spring来创建)
举个栗子:
图解:
可以发现,使用IOC方式,降低了耦合(解耦),不在编译期进行依赖,只在运行时进行依赖(联系)
自定义IOC容器:
介绍:
需求
实现service层与dao层代码解耦合
步骤分析
创建java项目,导入自定义IOC相关坐标(依赖,此依赖是对应包,不是联系)
编写Dao接口和实现类
编写Service接口和实现类
编写测试代码
实现:
创建java项目,导入自定义IOC相关坐标:
< dependencies>
< dependency>
< groupId> dom4j</ groupId>
< artifactId> dom4j</ artifactId>
< version> 1.6.1</ version>
</ dependency>
< dependency>
< groupId> jaxen</ groupId>
< artifactId> jaxen</ artifactId>
< version> 1.1.6</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId> < version> 4.12</ version>
</ dependency>
</dependencies
编写Dao接口和实现类:
public interface IUserDao {
public void save ( ) ;
}
public class UserDaoImpl implements IUserDao {
public void save ( ) {
System . out. println ( "dao被调用了,保存成功..." ) ;
}
}
编写Service接口和实现类 :
public interface IUserService {
public void save ( ) ;
}
public class UserServiceImpl implements IUserService {
public void save ( ) {
IUserDao userDao = new UserDaoImpl ( ) ;
userDao. save ( ) ;
}
}
编写测试代码:
public class SpringTest {
@Test
public void test1 ( ) throws IllegalAccessException , InstantiationException , ClassNotFoundException
{
IUserService userService = new UserServiceImpl ( ) ;
userService. save ( ) ;
}
}
问题:
当前service对象和dao对象耦合度太高,而且每次new的都是一个新的对象,导致服务器压力过大
解耦合的原则是编译期不依赖,而运行期依赖就行了
我们可以使用反射
public class UserServiceImpl implements IUserService {
public void save ( ) throws ClassNotFoundException {
IUserDao userDao = ( IUserDao ) Class . forName ( "com.lagou.dao.impl.UserDaoImpl" ) . newInstance ( ) ;
userDao. save ( ) ;
}
}
说明一下:一般配置文件的读取,都会用到对应的xml解析方式
如dom4j方式(其实也是由IO流来进行读取,只是由各种程序操作而已,形成了一种方式)
这上面也是有问题的,如以下图解:
其中我们自己创建的map集合,可以说是我们自定义的IOC容器(就是自己创建一个类似于IOC容器的方式)
接下来我们根据上图来编写自定义的IOC容器
beans.xml配置文件(xml名称基本可以随便写):
< beans>
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" >
</ bean>
</ beans>
核心代码(后面会多次提到):
package com. lagou. utils ;
import org. dom4j. Document ;
import org. dom4j. Element ;
import org. dom4j. io. SAXReader ;
import java. io. InputStream ;
import java. util. HashMap ;
import java. util. List ;
import java. util. Map ;
public class BeanFactory {
private static Map < String , Object > iocmap = new HashMap < > ( ) ;
static {
InputStream resourceAsStream =
BeanFactory . class . getClassLoader ( ) . getResourceAsStream ( "beans.xml" ) ;
SAXReader saxReader = new SAXReader ( ) ;
try {
Document read = saxReader. read ( resourceAsStream) ;
String xpath = "//bean" ;
List < Element > list = read. selectNodes ( xpath) ;
for ( Element element : list) {
String id = element. attributeValue ( "id" ) ;
String aClass = element. attributeValue ( "class" ) ;
Object o = Class . forName ( aClass) . newInstance ( ) ;
iocmap. put ( id, o) ;
}
} catch ( Exception ex) {
ex. printStackTrace ( ) ;
}
}
}
修改UserServiceImpl实现类 :
public class UserServiceImpl implements IUserService {
public void save ( ) throws ClassNotFoundException , IllegalAccessException , InstantiationException
{
IUserDao userDao = ( IUserDao ) BeanFactory . getBean ( "userDao" ) ;
userDao. save ( ) ;
}
}
知识小结:
上面就可以说是一个小的IOC容器了,即可以将IOC容器看成一个map集合,后面会多次用这个解释
注意:配置文件是会识别空格的,所以最好要严谨的写,否则可能就会报错,因为通常情况下,java文件名称是没有空格的
若有空格,需要特殊处理,具体去百度搜索
Spring快速入门:
Spring帮我们封装(编写)好了类似于上面的核心代码,那么我们只需要编写对应配置文件就可以操作了
介绍:
需求:借助spring的IOC实现service层与dao层代码解耦合:
步骤分析:
实现:
创建java项目,导入spring开发基本坐标:
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.1.5.RELEASE</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.12</ version>
</ dependency>
</ dependencies>
package com. lagou. dao ;
public interface IUserDao {
public void save ( ) ;
}
package com. lagou. dao. impl ;
import com. lagou. dao. IUserDao ;
public class UserDaoImpl implements IUserDao {
@Override
public void save ( ) {
System . out. println ( "dao被调用了" ) ;
}
}
package com. lagou. test ;
import com. lagou. dao. IUserDao ;
import org. junit. Test ;
import org. springframework. context. ApplicationContext ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class SpringTest {
@Test
public void text1 ( ) {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
userDao. save ( ) ;
}
}
很明显:创建上下文的这个对象时,该对象的内部就帮我们执行了类似于核心代码的所有操作
使得后面我们可以使用对应方法来获得IOC容器反射出来的对象
这个测试类,就可以当作service层的操作
<?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 = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
</ beans>
知识小结:
Spring的开发步骤:
Spring相关API:
API继承体系介绍:
Spring的API体系异常庞大,我们现在只关注两个BeanFactory和ApplicationContext
从上到下(上面是最底层的):
紫色:接口
浅绿色:抽象类
深绿色:实现类
BeanFactory:
从图看是底层接口
BeanFactory是 IOC 容器的核心接口,它定义了IOC的基本功能
特点:在第一次调用getBean()方法时,创建指定对象的实例
BeanFactory beanFactory = new XmlBeanFactory ( new ClassPathResource ( "applicationContext.xml" ) ) ;
@Test
public void text2 ( ) {
BeanFactory xmlBeanFactory = new XmlBeanFactory ( new
ClassPathResource ( "applicationContext.xml" ) ) ;
IUserDao userDao = ( IUserDao ) xmlBeanFactory. getBean ( "userDao" ) ;
userDao. save ( ) ;
}
从上可以得出(可能会有改变,所以具体只看实现类,而不看下面的说明):
ApplicationContext:
代表应用上下文对象,可以获得spring中IOC容器的Bean对象
特点:在spring容器启动时,加载并创建所有对象的实例
常用实现类:
ApplicationContext app = new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
常用方法:
package com. lagou. test ;
import com. lagou. dao. IUserDao ;
import org. junit. Test ;
import org. springframework. beans. factory. BeanFactory ;
import org. springframework. beans. factory. xml. XmlBeanFactory ;
import org. springframework. context. ApplicationContext ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
import org. springframework. core. io. ClassPathResource ;
public class SpringTest {
@Test
public void text1 ( ) {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = classPathXmlApplicationContext. getBean ( "userDao" , IUserDao . class ) ;
userDao. save ( ) ;
}
}
知识小结:
Spring配置文件:
Bean标签基本配置:
Bean标签范围配置:
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" scope = " singleton" > </ bean>
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" scope = " prototype" > </ bean>
scope属性指对象的作用范围,取值如下:
singleton:单例的(类似于单例模式),那么只有一个对应对象,也就是说
我们根据id取值时,就是使用一个对象,会将对应的对象,放入map集合中
prototype:多例的,那么会获得多个对象,也就是说,当你获得一个对象时,就会创建一个新的对象并返回
也就是说,不会放入集合中
每次请求都会去创建对象并返回,虽然调用对应方法时
不会去map集合找,但也会根据参数和id来进行判断是否一致,不一致还是会报错的
下面的request和session不止会存在容器里,还会存在对应域中
当然了,只有在服务器里才可以设置,否则是会提示没有对应属性值的
测试:
@Test
public void text3 ( ) {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
IUserDao userDao1 = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
System . out. println ( userDao) ;
System . out. println ( userDao1) ;
}
@Test
public void text4 ( ) {
ApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
IUserDao userDao1 = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
System . out. println ( userDao) ;
System . out. println ( userDao1) ;
}
上面两个就代表了实例方式不同,而ApplicationContext和BeanFactory代表操作不同(按照上面的来进行)
所以BeanFactory最后的获得对象,是按照上面实例方式的获得
也就是说当scope的取值为singleton时,ApplicationContext全部操作,BeanFactory获得操作(map)
当scope的取值为prototype时,ApplicationContext获得操作(无map),BeanFactory获得操作(无map)
也就是说,使用了多例的bean,不会在全部操作中进行放入map集合
而是再调用对应方法时,直接获取新创建的对象
Bean生命周期配置:
测试:
package com. lagou. dao. impl ;
import com. lagou. dao. IUserDao ;
public class UserDaoImpl implements IUserDao {
public void init ( ) {
System . out. println ( "初始化" ) ;
}
public void destroy ( ) {
System . out. println ( "销毁" ) ;
}
@Override
public void save ( ) {
System . out. println ( "dao被调用了" ) ;
}
}
@Test
public void text5 ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
System . out. println ( userDao) ;
classPathXmlApplicationContext. close ( ) ;
}
Bean实例化三种方式:
无参构造方法实例化
工厂静态方法实例化
工厂普通方法实例化
无参构造方法实例化:
它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败
即报错(idea通常也会有提示报红)
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" />
工厂静态方法实例化 :
应用场景
依赖的jar包中有个A类,A类中有个静态方法m1,m1方法的返回值是一个B对象
如果我们频繁使用B对象,此时我们可以将B对象的创建权交给spring的IOC容器
以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得
我们可以通过如下操作,进行配置
public class StaticFactoryBean {
public static IUserDao createUserDao ( ) {
return new UserDaoImpl ( ) ;
}
}
< bean id = " userDao" class = " com.lagou.factory.StaticFactoryBean" factory-method = " createUserDao" > </ bean>
工厂普通方法实例化 :
应用场景
依赖的jar包中有个A类,A类中有个普通方法m1,m1方法的返回值是一个B对象,如果我们频繁使用B对象
此时我们可以将B对象的创建权交给spring的IOC容器,以后我们在使用B对象时,无需调用A类中的m1方法,直接从IOC容器获得
与上面的工厂静态方法实例化类似,只是不是静态的而已
public class DynamicFactoryBean {
public IUserDao createUserDao ( ) {
return new UserDaoImpl ( ) ;
}
}
< bean id = " dynamicFactoryBean" class = " com.lagou.factory.DynamicFactoryBean" > </ bean>
< bean id = " userDao" factory-bean = " dynamicFactoryBean" factory-method = " createUserDao" > </ bean>
其实第二个bean标签是可以写在第一个前面的,即可以知道,Spring读取配置文件的方式
基本是全部读取(一个对象),然后根据对象,操作信息依次放入或者将对应信息(后面的解释多以这种形式)
依次放入(一般是拿出进行操作,在后面的"认为是map之后的操作"有具体说明)map集合(其中也有其他操作,就与Mybatis的对应MappedStatement对象类似)
也就相当于一个bean标签可以看成就是一个对象
以此来说,那么我们将factory-bean=“dynamicFactoryBean” factory-method="createUserDao"写在第一个标签里
那么会操作不了factory-bean="dynamicFactoryBean"的(因为只能操作其他对象的,不操作本对象)
即factory-method="createUserDao"会显示找不到对应静态方法(因为只有普通方法)
所以由于jar包的内容,基本上与工厂静态方法实例化和工厂普通方法实例化的类的操作类似,即返回对应类的对象
所以也就通常用于jar包的类
我们自己写的类,一般就会使用无参构造方法实例化,因为我们通常不会这样操作
Bean依赖注入概述:
依赖注入 DI(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是代码中不可能出现没有依赖的情况
IOC 解耦只是降低他们的依赖关系,但不会消除
例如:业务层仍会调用持久层的方法
那这种业务层和持久层的依赖关系,在使用 Spring 之后,就让 Spring 来维护了
简单的说,就是通过框架把持久层对象传入业务层,而不用我们自己去获取
测试说明:
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" > </ bean>
package com. lagou. service ;
public interface IUserService {
public void save ( ) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. IUserDao ;
import com. lagou. service. IUserService ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
public class UserServiceImpl implements IUserService {
@Override
public void save ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserDao userDao = ( IUserDao ) classPathXmlApplicationContext. getBean ( "userDao" ) ;
userDao. save ( ) ;
}
}
@Test
public void text6 ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserService userService = ( IUserService )
classPathXmlApplicationContext. getBean ( "UserService" ) ;
userService. save ( ) ;
}
为了解决上述情况,我们有如下方式
Bean依赖注入方式:
构造方法(有参,不设置默认无参):
在UserServiceImpl中创建有参构造:
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" >
< constructor-arg name = " userDao" ref = " userDao" > </ constructor-arg>
</ bean>
package com. lagou. service. impl ;
import com. lagou. dao. IUserDao ;
import com. lagou. service. IUserService ;
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public UserServiceImpl ( IUserDao userDao) {
this . userDao = userDao;
}
@Override
public void save ( ) {
userDao. save ( ) ;
}
}
@Test
public void text6 ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserService userService = ( IUserService )
classPathXmlApplicationContext. getBean ( "UserService" ) ;
userService. save ( ) ;
}
}
这就是反射的功能强大之处,基本上可以对构造信息进行操作,如何操作,那就看你的程序是怎么操作的
set方法:
package com. lagou. service. impl ;
import com. lagou. dao. IUserDao ;
import com. lagou. service. IUserService ;
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public void setUserDao ( IUserDao userDao) {
this . userDao = userDao;
}
@Override
public void save ( ) {
userDao. save ( ) ;
}
}
@Test
public void text6 ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserService userService = ( IUserService )
classPathXmlApplicationContext. getBean ( "UserService" ) ;
userService. save ( ) ;
}
<?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 = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" >
< property name = " userDao" ref = " userDao" > </ property>
</ bean>
</ beans>
上面两个方式,set方式更加常用
P命名空间注入:
P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下
首先,需要引入P命名空间:
其次,需要修改注入方式:
<?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" >
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" p: userDao-ref= " userDao" >
</ bean>
</ beans>
所以说p命名空间注入实际上也就是set方式的注入
Bean依赖注入的数据类型 :
依赖注入,一般只能注入一个参数 ,所以我们通常写上多个property标签,来进行依赖注入
因为Spring是符合对应set方法的规则的,对应set方法一般就是一个参数,如果你非要写两个参数,那不用说,就会报错
打印出不匹配对应规则的错误
上面操作,都是注入Bean对象,除了对象的引用可以注入,普通数据类型和集合都可以在容器中进行注入
注入数据的三种数据类型
普通数据类型
引用数据类型
集合数据类型
其中引用数据类型,此处就不再说明(赘述)了,之前的操作都是对UserDao对象的引用进行注入的
下面将以set方法注入为例,演示普通数据类型和集合数据类型的注入
注入普通数据类型(注意修改前面代码):
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" >
< property name = " username" value = " 哈哈哈" > </ property>
< property name = " age" value = " 18" > </ property>
</ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" >
< property name = " userDao" ref = " userDao" > </ property>
</ bean>
package com. lagou. dao. impl ;
import com. lagou. dao. IUserDao ;
public class UserDaoImpl implements IUserDao {
private String username;
private Integer age;
public String getUsername ( ) {
return username;
}
public void setUsername ( String username) {
this . username = username;
}
public Integer getAge ( ) {
return age;
}
public void setAge ( Integer age) {
this . age = age;
}
@Override
public void save ( ) {
System . out. println ( username) ;
System . out. println ( age) ;
System . out. println ( "dao被调用了" ) ;
}
}
注入集合数据类型 :
List集合注入,Set集合注入 ,Array数组注入 ,Map集合注入,Properties配置注入:
package com. lagou. dao. impl ;
import com. lagou. dao. IUserDao ;
import java. util. * ;
public class UserDaoImpl implements IUserDao {
private String username;
private Integer age;
private List < Object > list;
private Set < Object > set;
private Object [ ] array;
private Map < String , Object > map;
private Properties properties;
public void setProperties ( Properties properties) {
this . properties = properties;
}
public void setMap ( Map < String , Object > map) {
this . map = map;
}
public void setArray ( Object [ ] array) {
this . array = array;
}
public void setSet ( Set < Object > set) {
this . set = set;
}
public void setList ( List < Object > list) {
this . list = list;
}
public void setUsername ( String username) {
this . username = username;
}
public void setAge ( Integer age) {
this . age = age;
}
@Override
public void save ( ) {
System . out. println ( list) ;
System . out. println ( set) ;
System . out. println ( Arrays . toString ( array) ) ;
System . out. println ( map) ;
System . out. println ( properties) ;
System . out. println ( age) ;
System . out. println ( username) ;
System . out. println ( "dao被调用了" ) ;
}
}
package com. lagou. domain ;
public class User {
private String username;
private Integer age;
public void setUsername ( String username) {
this . username = username;
}
public void setAge ( Integer age) {
this . age = age;
}
@Override
public String toString ( ) {
return "User{" +
"username='" + username + '\'' +
", age=" + age +
'}' ;
}
}
package com. lagou. service. impl ;
import com. lagou. dao. IUserDao ;
import com. lagou. service. IUserService ;
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
public void setUserDao ( IUserDao userDao) {
this . userDao = userDao;
}
@Override
public void save ( ) {
userDao. save ( ) ;
}
}
< bean id = " user" class = " com.lagou.domain.User" >
< property name = " username" value = " 哈哈好" > </ property>
< property name = " age" value = " 20" > </ property>
</ bean>
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" >
< property name = " username" value = " 哈哈哈" > </ property>
< property name = " age" value = " 18" > </ property>
< property name = " list" >
< list>
< value> aaa</ value>
< ref bean = " user" > </ ref>
</ list>
</ property>
< property name = " set" >
< set>
< value> bbb</ value>
< ref bean = " user" > </ ref>
</ set>
</ property>
< property name = " array" >
< array>
< value> ccc</ value>
< ref bean = " user" > </ ref>
</ array>
</ property>
< property name = " map" >
< map>
< entry key = " k1" value = " ddd" > </ entry>
< entry key = " k2" value-ref = " user" > </ entry>
</ map>
</ property>
< property name = " properties" >
< props>
< prop key = " k1" > v1</ prop>
< prop key = " k2" > v2</ prop>
< prop key = " k3" > v3</ prop>
</ props>
</ property>
</ bean>
< bean id = " UserService" class = " com.lagou.service.impl.UserServiceImpl" >
< property name = " userDao" ref = " userDao" > </ property>
</ bean>
</ beans>
@Test
public void text6 ( ) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
IUserService userService = ( IUserService )
classPathXmlApplicationContext. getBean ( "UserService" ) ;
userService. save ( ) ;
}
package com. lagou. dao ;
public interface IUserDao {
public void save ( ) ;
}
package com. lagou. service ;
public interface IUserService {
public void save ( ) ;
}
配置文件模块化:
实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大
所以,可以将部分配置拆解到其他配置文件中,也就是所谓的配置文件模块化
并列的多个配置文件:
ApplicationContext act =
new
ClassPathXmlApplicationContext ( "beans1.xml" , "beans2.xml" , "..." ) ;
主从配置文件:
< import resource = " applicationContext-xxx.xml" />
< import resource = " classpath:applicationContext-user.xml" > </ import>
注意:
同一个xml中不能出现相同名称的bean,如果出现会报错
多个xml如果出现相同名称的bean,不会报错,但是后加载的会覆盖前加载的bean(一般来说导入的通常相当于在对应位置的顺序,所以如果你的标签在导入的代码前面,那么被导入的覆盖)
因为同样id只会在同一个配置文件里进行检查,即在对象里进行检查
而之所以会覆盖,是因为在进行依次放入map集合中,后放入的一定是修改操作,也就是覆盖,这是map集合自身的作用
知识小结:
Spring的重点配置
DbUtils(IOC实战):
DbUtils是什么?
DbUtils是Apache的一款用于简化Dao代码的工具类,它底层封装了JDBC技术
核心对象:
QueryRunner queryRunner = new QueryRunner ( DataSource dataSource) ;
核心方法:
举个栗子:
查询数据库所有账户信息到Account实体中
public class DbUtilsTest {
@Test
public void findAllTest ( ) throws Exception {
QueryRunner queryRunner = new QueryRunner ( JdbcUtils . getDataSource ( ) ) ;
String sql = "select * from account" ;
List < Account > list = queryRunner. query ( sql, new BeanListHandler < Account >
( Account . class ) ) ;
for ( Account account : list) {
System . out. println ( account) ;
}
}
}
Spring的xml整合DbUtils :
介绍 :
需求:
基于Spring的xml配置实现账户的CRUD案例
步骤分析:
实现:
准备数据库环境:
CREATE DATABASE ` spring_db` ;
USE ` spring_db` ;
CREATE TABLE ` account` (
` id` int ( 11 ) NOT NULL AUTO_INCREMENT ,
` name` varchar ( 32 ) DEFAULT NULL ,
` money` double DEFAULT NULL ,
PRIMARY KEY ( ` id` )
) ;
insert into ` account` ( ` id` , ` name` , ` money` ) values ( 1 , 'tom' , 1000 ) ,
( 2 , 'jerry' , 1000 ) ;
创建java项目,导入坐标:
< dependencies>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 5.1.47</ version>
</ dependency>
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> druid</ artifactId>
< version> 1.1.9</ version>
</ dependency>
< dependency>
< groupId> commons-dbutils</ groupId>
< artifactId> commons-dbutils</ artifactId>
< version> 1.6</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> 5.1.5.RELEASE</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.12</ version>
</ dependency>
</ dependencies>
编写Account实体类:
package com. lagou. domain ;
public class Account {
private Integer id;
private String name;
private Double money;
@Override
public String toString ( ) {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}' ;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Double getMoney ( ) {
return money;
}
public void setMoney ( Double money) {
this . money = money;
}
}
编写AccountDao接口和实现类 :
package com. lagou. dao ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountDao {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. dao. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import org. apache. commons. dbutils. QueryRunner ;
import org. apache. commons. dbutils. handlers. BeanHandler ;
import org. apache. commons. dbutils. handlers. BeanListHandler ;
import java. sql. SQLException ;
import java. util. List ;
public class AccountDaoImpl implements AccountDao {
private QueryRunner qr;
public void setQr ( QueryRunner qr) {
this . qr = qr;
}
@Override
public List < Account > findAll ( ) {
List < Account > query = null ;
String sql = "select * from account" ;
try {
query = qr. query ( sql, new BeanListHandler < Account > ( Account . class ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return query;
}
@Override
public Account findById ( Integer id) {
Account account = null ;
String sql = "select * from account where id = ?" ;
try {
account = qr. query ( sql, new BeanHandler < Account > ( Account . class ) , id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return account;
}
@Override
public void save ( Account account) {
String sql = "insert into account values(null,?,?)" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void update ( Account account) {
String sql = "update account set name = ?,money = ? where id = ?" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) , account. getId ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void delete ( Integer id) {
String sql = "delete from account where id = ?" ;
try {
qr. update ( sql, id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
编写AccountService接口和实现类:
package com. lagou. service ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountService {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import java. util. List ;
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao ( AccountDao accountDao) {
this . accountDao = accountDao;
}
@Override
public List < Account > findAll ( ) {
return accountDao. findAll ( ) ;
}
@Override
public Account findById ( Integer id) {
return accountDao. findById ( id) ;
}
@Override
public void save ( Account account) {
accountDao. save ( account) ;
}
@Override
public void update ( Account account) {
accountDao. update ( account) ;
}
@Override
public void delete ( Integer id) {
accountDao. delete ( id) ;
}
}
编写spring核心配置文件:
applicationContext.xml:
注意:我们在使用set注入时,必须有对应的set方法,通常jar包都是有对应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 = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " com.mysql.jdbc.Driver" />
< property name = " url" value = " jdbc:mysql:///spring_db?characterEncoding=utf8" />
< property name = " username" value = " root" />
< property name = " password" value = " 123456" />
</ bean>
< bean id = " qr" class = " org.apache.commons.dbutils.QueryRunner" >
< constructor-arg name = " ds" ref = " dataSource" />
</ bean>
< bean id = " accountdao" class = " com.lagou.dao.impl.AccountDaoImpl" >
< property name = " qr" ref = " qr" />
</ bean>
< bean id = " accountservice" class = " com.lagou.service.impl.AccountServiceImpl" >
< property name = " accountDao" ref = " accountdao" />
</ bean>
</ beans>
编写测试代码:
package com. lagou. test ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import org. junit. Test ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
import java. util. List ;
public class AccountServiceTest {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
AccountService accountService = ( AccountService )
classPathXmlApplicationContext. getBean ( "accountservice" ) ;
@Test
public void testsave ( ) {
Account account = new Account ( ) ;
account. setName ( "张三" ) ;
account. setMoney ( 1000.0 ) ;
accountService. save ( account) ;
}
@Test
public void testFindById ( ) {
Account account = accountService. findById ( 3 ) ;
System . out. println ( account) ;
}
@Test
public void testFindAll ( ) {
List < Account > all = accountService. findAll ( ) ;
for ( Account account : all) {
System . out. println ( account) ;
}
}
@Test
public void testUpdate ( ) {
Account account = new Account ( ) ;
account. setId ( 3 ) ;
account. setName ( "李四" ) ;
account. setMoney ( 2000.0 ) ;
accountService. update ( account) ;
}
@Test
public void testDelete ( ) {
accountService. delete ( 3 ) ;
}
}
抽取jdbc配置文件 :
applicationContext.xml加载jdbc.properties配置文件获得连接信息
首先,需要引入context命名空间和约束路径:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
# #是注释符号,当上面的数据被读取时,当作键值对来操作读取
# 一般其他配置文件都是使用${对应变量},也就是读取key的value的值来获得后面的数据
# 一般value的值都是直接替换的,若加上""肯定会报错,不能有两个"",且底层无限循环
# 因为java会判断变化失败,继续变化
# 这里之所以不像java在字符串需要""来包括,那是因为使用""来包括,是java需要判断对应类型而使用的
# 最终的结果,还是文件是的二进制的显示,也就是字节,java只是用来判断类型,所以可以看到类型的报错
# 但实际上在文件里显示,就不会加上所谓的"",即没有类型的概念,单纯的替换字节显示
# 但被java获得时,基本都会按照字符串来进行包括
# 实际上打印时,都会变成字节来打印,变成字符图案显示,也就是解码后的显示
<?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: property-placeholder location = " classpath:jdbc.properties" > </ context: property-placeholder>
< bean id = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " ${jdbc.driverClassName}" />
< property name = " url" value = " ${jdbc.url}" />
< property name = " username" value = " ${jdbc.username}" />
< property name = " password" value = " ${jdbc.password}" />
</ bean>
< bean id = " qr" class = " org.apache.commons.dbutils.QueryRunner" >
< constructor-arg name = " ds" ref = " dataSource" />
</ bean>
< bean id = " accountdao" class = " com.lagou.dao.impl.AccountDaoImpl" >
< property name = " qr" ref = " qr" />
</ bean>
< bean id = " accountservice" class = " com.lagou.service.impl.AccountServiceImpl" >
< property name = " accountDao" ref = " accountdao" />
</ bean>
</ beans>
知识小结:
Spring注解开发:
xml和注解,基本都是通过反射来简便的,所以说,对于运行的效率
实际上就是启动时间,因为启动后,他们的作用已经作用完了,如IOC容器,都创建好了,之后就不会再次读取
所以说主要看启动时间,但启动时间的快慢,并不影响程序,所以他们的运行效率都是差不多的
即读取xml和读取注解运行效率差不多
Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势
注解代替xml配置文件可以简化配置,提高开发效率
Spring常用注解:
介绍:
Spring常用注解主要是替代 < bean> 的配置
图解:
下图中,前面四个@Component(其他三个可以认为是这个的别名),@Controller,@Service,@Repository作用都是创建对应对象放在IOC容器中
只是我们可以根据名称来进行判断这是哪个层,所以在不规范的情况下,这四个可以随便用
而在后面四个,虽然作用都是依赖注入,但是需要对应条件来使用,如类型,如需要结合
其中类似于property的是直接赋值,而不是调用set方法
无论是什么框架,注解和xml的作用基本类似,且谁后配置,谁进行覆盖(对应操作的地方都会有唯一标识,使得可以进行覆盖)
一般的框架都会自动扫描对应注解位置
也就基本得到了对应类的位置(这样完全受注解位置影响,也就是硬编码问题)
所以这就是可以使用反射进行获取全路径名,而创建对象的原因
从而实现注解的作用(内容有其他作用),并使用反射进行操作
而xml一般需要自己指定读取,从而实现xml的作用(内容有其他作用,且有全路径名的内容),并使用反射进行操作
说明:
JDK11以后完全移除了javax扩展导致不能使用@resource注解
需要maven引入依赖
< dependency>
< groupId> javax.annotation</ groupId>
< artifactId> javax.annotation-api</ artifactId>
< version> 1.3.2</ version>
</ dependency>
注意:
再Spring里,需要自己进行扫描注解并使用
所以使用注解进行开发时,需要在applicationContext.xml中配置组件扫描
作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置的类、字段和方法
< context: component-scan base-package = " com.lagou" />
实现:
Bean实例化(IOC):
< bean id = " userDao" class = " com.lagou.dao.impl.UserDaoImpl" > </ bean>
使用@Component,@Controller,@Service,@Repository标识UserDaoImpl进行Spring实例化
@Service ( value = "accountservice" )
public class AccountServiceImpl implements AccountService {
}
属性依赖注入(DI):
< bean id = " userService" class = " com.lagou.service.impl.UserServiceImpl" >
< property name = " userDao" ref = " userDaoImpl" />
</ bean>
使用@Autowired或者@Autowired+@Qulifier或者@Resource进行userDao的注入
@Resource ( name = "accountdao" )
private AccountDao aDao;
@Value:
使用@Value进行字符串的注入,结合SPEL表达式获得配置参数
@Value ( "注入普通属性" )
private String str;
@Value ( "${jdbc.driverClassName}" )
private String driver;
@Scope:
< bean scope = " " />
使用@Scope标注Bean的范围:
@Service ( value = "accountservice" )
@Scope ( "prototype" )
Bean生命周期 :
< bean init-method = " init" destroy-method = " destory" />
使用@PostConstruct标注初始化方法,使用@PreDestroy标注销毁方法
@PostConstruct
public void init ( ) {
System . out. println ( "初始化方法...." ) ;
}
@PreDestroy
public void destroy ( ) {
System . out. println ( "销毁方法....." ) ;
}
Spring常用注解整合DbUtils :
步骤分析:
将前面进行修改之后,如下
package com. lagou. dao ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountDao {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. dao. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import org. apache. commons. dbutils. QueryRunner ;
import org. apache. commons. dbutils. handlers. BeanHandler ;
import org. apache. commons. dbutils. handlers. BeanListHandler ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Repository ;
import java. sql. SQLException ;
import java. util. List ;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner qr;
@Override
public List < Account > findAll ( ) {
List < Account > query = null ;
String sql = "select * from account" ;
try {
query = qr. query ( sql, new BeanListHandler < Account > ( Account . class ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return query;
}
@Override
public Account findById ( Integer id) {
Account account = null ;
String sql = "select * from account where id = ?" ;
try {
account = qr. query ( sql, new BeanHandler < Account > ( Account . class ) , id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return account;
}
@Override
public void save ( Account account) {
String sql = "insert into account values(null,?,?)" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void update ( Account account) {
String sql = "update account set name = ?,money = ? where id = ?" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) , account. getId ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void delete ( Integer id) {
String sql = "delete from account where id = ?" ;
try {
qr. update ( sql, id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
package com. lagou. domain ;
public class Account {
private Integer id;
private String name;
private Double money;
@Override
public String toString ( ) {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}' ;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Double getMoney ( ) {
return money;
}
public void setMoney ( Double money) {
this . money = money;
}
}
package com. lagou. service ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountService {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service ( value = "accountservice" )
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao aDao;
public void setAccountDao ( AccountDao accountDao) {
this . aDao = accountDao;
}
@Override
public List < Account > findAll ( ) {
return aDao. findAll ( ) ;
}
@Override
public Account findById ( Integer id) {
return aDao. findById ( id) ;
}
@Override
public void save ( Account account) {
aDao. save ( account) ;
}
@Override
public void update ( Account account) {
aDao. update ( account) ;
}
@Override
public void delete ( Integer id) {
aDao. delete ( id) ;
}
}
package com. lagou. test ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import org. junit. Test ;
import org. springframework. context. support. ClassPathXmlApplicationContext ;
import java. util. List ;
public class AccountServiceTest {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new
ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
AccountService accountService = ( AccountService )
classPathXmlApplicationContext. getBean ( "accountservice" ) ;
@Test
public void testsave ( ) {
Account account = new Account ( ) ;
account. setName ( "张三" ) ;
account. setMoney ( 1000.0 ) ;
accountService. save ( account) ;
}
@Test
public void testFindById ( ) {
Account account = accountService. findById ( 3 ) ;
System . out. println ( account) ;
}
@Test
public void testFindAll ( ) {
List < Account > all = accountService. findAll ( ) ;
for ( Account account : all) {
System . out. println ( account) ;
}
}
@Test
public void testUpdate ( ) {
Account account = new Account ( ) ;
account. setId ( 3 ) ;
account. setName ( "李四" ) ;
account. setMoney ( 2000.0 ) ;
accountService. update ( account) ;
}
@Test
public void testDelete ( ) {
accountService. delete ( 3 ) ;
}
}
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
<?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.lagou" />
< context: property-placeholder location = " classpath:jdbc.properties" > </ context: property-placeholder>
< bean id = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " ${jdbc.driverClassName}" />
< property name = " url" value = " ${jdbc.url}" />
< property name = " username" value = " ${jdbc.username}" />
< property name = " password" value = " ${jdbc.password}" />
</ bean>
< bean id = " qr" class = " org.apache.commons.dbutils.QueryRunner" >
< constructor-arg name = " ds" ref = " dataSource" />
</ bean>
</ beans>
从这里可以发现,上面并没有完全的使用注解的方式,也就是说上面的方式是注解和xml的结合使用
为了完全的只使用注解,看如下内容
Spring新注解:
使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
由于前面的xml配置文件,不好进行配置,那么我们就引出了替代对应xml的文件,也就是我们所说的配置类
这个配置类相当于上面的xml文件,只是这个是以类来保存的,即可以全部使用注解来开发了
之所以配置类可以与xml一样进行读取,是因为我们不止可以读取xml配置文件,也可以读取配置类
即扫描被@Configuration注解的类
被扫描后,那么会根据自身信息进行操作,扫描到一定的注解,那么就会根据这个注解的信息来进行操作
如创建对象放入map集合,或者加载properties到全局,或者扫描对应包,又或者导入其他配置类
使得我们读取xml获得的信息,变得在注解获得的信息是类似的,即实现了纯注解开发
图解:
Spring纯注解整合DbUtils:
步骤分析:
package com. lagou. config ;
import com. alibaba. druid. pool. DruidDataSource ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ;
import javax. sql. DataSource ;
@Configuration
public class DataSourceConfig {
@Value ( "${jdbc.driverClassName}" )
private String driver;
@Value ( "${jdbc.url}" )
private String url;
@Value ( "${jdbc.username}" )
private String username;
@Value ( "${jdbc.password}" )
private String password;
@Bean ( "dataSource" )
public DataSource getDataSource ( ) {
DruidDataSource druidDataSource = new DruidDataSource ( ) ;
druidDataSource. setDriverClassName ( driver) ;
druidDataSource. setUrl ( url) ;
druidDataSource. setUsername ( username) ;
druidDataSource. setPassword ( password) ;
return druidDataSource;
}
}
package com. lagou. config ;
import org. apache. commons. dbutils. QueryRunner ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. context. annotation. * ;
import javax. sql. DataSource ;
@Configuration
@ComponentScan ( "com.lagou" )
@PropertySource ( "classpath:jdbc.properties" )
@Import ( DataSourceConfig . class )
public class SpringConfig {
@Bean ( "queryRunner" )
public QueryRunner getQueryRunner ( @Autowired DataSource dataSource) {
QueryRunner queryRunner = new QueryRunner ( dataSource) ;
return queryRunner;
}
}
package com. lagou. dao ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountDao {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. dao. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import org. apache. commons. dbutils. QueryRunner ;
import org. apache. commons. dbutils. handlers. BeanHandler ;
import org. apache. commons. dbutils. handlers. BeanListHandler ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Repository ;
import java. sql. SQLException ;
import java. util. List ;
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private QueryRunner qr;
@Override
public List < Account > findAll ( ) {
List < Account > query = null ;
String sql = "select * from account" ;
try {
query = qr. query ( sql, new BeanListHandler < Account > ( Account . class ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return query;
}
@Override
public Account findById ( Integer id) {
Account account = null ;
String sql = "select * from account where id = ?" ;
try {
account = qr. query ( sql, new BeanHandler < Account > ( Account . class ) , id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
return account;
}
@Override
public void save ( Account account) {
String sql = "insert into account values(null,?,?)" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void update ( Account account) {
String sql = "update account set name = ?,money = ? where id = ?" ;
try {
qr. update ( sql, account. getName ( ) , account. getMoney ( ) , account. getId ( ) ) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
@Override
public void delete ( Integer id) {
String sql = "delete from account where id = ?" ;
try {
qr. update ( sql, id) ;
} catch ( SQLException e) {
e. printStackTrace ( ) ;
}
}
}
package com. lagou. domain ;
public class Account {
private Integer id;
private String name;
private Double money;
@Override
public String toString ( ) {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}' ;
}
public Integer getId ( ) {
return id;
}
public void setId ( Integer id) {
this . id = id;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public Double getMoney ( ) {
return money;
}
public void setMoney ( Double money) {
this . money = money;
}
}
package com. lagou. service ;
import com. lagou. domain. Account ;
import java. util. List ;
public interface AccountService {
public List < Account > findAll ( ) ;
public Account findById ( Integer id) ;
public void save ( Account account) ;
public void update ( Account account) ;
public void delete ( Integer id) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. AccountDao ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service ( value = "accountservice" )
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao aDao;
public void setAccountDao ( AccountDao accountDao) {
this . aDao = accountDao;
}
@Override
public List < Account > findAll ( ) {
return aDao. findAll ( ) ;
}
@Override
public Account findById ( Integer id) {
return aDao. findById ( id) ;
}
@Override
public void save ( Account account) {
aDao. save ( account) ;
}
@Override
public void update ( Account account) {
aDao. update ( account) ;
}
@Override
public void delete ( Integer id) {
aDao. delete ( id) ;
}
}
package com. lagou. test ;
import com. lagou. config. SpringConfig ;
import com. lagou. domain. Account ;
import com. lagou. service. AccountService ;
import org. junit. Test ;
import org. springframework. context. annotation. AnnotationConfigApplicationContext ;
import javax. sql. DataSource ;
import java. util. List ;
public class AccountServiceTest {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new
AnnotationConfigApplicationContext ( SpringConfig . class ) ;
AccountService accountService =
( AccountService ) annotationConfigApplicationContext. getBean ( "accountservice" ) ;
@Test
public void testsave ( ) {
Account account = new Account ( ) ;
account. setName ( "张三" ) ;
account. setMoney ( 1000.0 ) ;
accountService. save ( account) ;
}
@Test
public void testFindById ( ) {
Account account = accountService. findById ( 3 ) ;
System . out. println ( account) ;
}
@Test
public void testFindAll ( ) {
List < Account > all = accountService. findAll ( ) ;
for ( Account account : all) {
System . out. println ( account) ;
}
DataSource accountService1 =
( DataSource ) annotationConfigApplicationContext. getBean ( "dataSource" ) ;
System . out. println ( accountService1) ;
}
@Test
public void testUpdate ( ) {
Account account = new Account ( ) ;
account. setId ( 3 ) ;
account. setName ( "李四" ) ;
account. setMoney ( 2000.0 ) ;
accountService. update ( account) ;
}
@Test
public void testDelete ( ) {
accountService. delete ( 3 ) ;
}
}
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
Spring整合Junit:
普通Junit测试问题:
在普通的测试类中,需要开发者手动加载配置文件并创建Spring容器,然后通过Spring相关API获得Bean实例
如果不这么做,那么无法从容器中获得对象
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext ( "applicationContext.xml" ) ;
AccountService accountService =
applicationContext. getBean ( AccountService . class ) ;
我们可以让SpringJunit负责创建Spring容器来简化这个操作,开发者可以直接在测试类注入Bean实例
但是需要将配置文件的名称告诉它
操作如下:
步骤分析:
导入spring集成Junit的坐标:
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-test</ artifactId>
< version> 5.1.5.RELEASE</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.12</ version>
< scope> test</ scope>
</ dependency>
使用@Runwith注解替换原来的运行器:
@RunWith ( SpringJUnit4ClassRunner . class )
public class AccountServiceTest {
}
使用@ContextConfiguration指定配置文件或配置类:
@ContextConfiguration ( classes = SpringConfig . class )
public class AccountServiceTest {
}
使用@Autowired注入需要测试的对象 :
public class AccountServiceTest {
@Autowired
private AccountServiceImpl accountService;
}
创建测试方法进行测试(结合了前面的代码) :
@Test
public void testFindAll ( ) {
List < Account > all = accountService. findAll ( ) ;
for ( Account account : all) {
System . out. println ( account) ;
}
}
最后:其实Spring是存在循环依赖的(多例的情况下,一般单例没有,或者说本来就解决的),我们知道,要放入map中,必然是需要对方都操作完毕,如果没有操作完毕,那么不会放入,所以如果他们之间存在一个循环,那么就都不会操作完毕了,这就是循环依赖的理论原因,具体可以看看这个博客:https://blog.csdn.net/qq_41421997/article/details/119993334
一般来说,当配置文件,注解,new,一起时,他们的优先级是(配置文件,注解),new,即若存在(配置文件,注解),那么就是(配置文件,注解),否则就是new,本质上就是替换,因为new在类出现时就操作了,而注入在类之后进行赋值,配置文件虽然也操作注入,但是与注解注入还是有区别的,其中在产生实例时,注解优先配置,然后注入也是一样,注解优先配置,比如当一个类里面的变量同时由注解和配置进行注入时,那么配置的优先(我后执行),既然配置的优先,那么配置就是最后操作的
执行顺序:new,注解,配置
最终结果出现:配置,注解,new
当然,随着版本的变化,其中注解和配置的先后顺序可能发生改变,了解并注意即可
注意:配置类也可以被mvc直接的指定,也可以使用xml来扫描他,他是可以被扫描的,就如xml引入xml一样,只不过由于xml不能引入类,所以交给了扫描来处理了
最后需要注意:操作对应的如@Component将一个类变成实例时,若其构造方法只有一个,并且是有参构造,通常会考虑对参数的注入,否则默认情况下基本都是无参构造,或者当构造方法足够多以及没有对应的bean时,那么就会报错,若要解决构造方法足够多,也就是一个类有多个构造函数,为了让 Spring 明确知道该使用哪个构造函数进行依赖注入,你可以在其中一个构造函数上加上 @Autowired注解(存在无参默认是无参的,否则需要指定)