前期配置
在setting配置中,对maven中的文件存放目录进行修改,然后创建maven的project即可
对IOCD理解
IOC:以前我要在java类中new,现在我把控制权交给Spring,他通过配置文件进行操作;
IOC:控制反转;
只要不是类和类间的连接性高,我们就可以称他为一个好的程序项目,Spring就是用来解决这个问题的
IOC制作步骤
1.导入spring坐标 5.1.9release、在pom.xml中
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
2.编写业务层与表现层(模拟)接口与实现类(在main中的java文件里创建)
接口
public interface UserService {
public void save();
}
实现类
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("user service running...");
}
}
3.建立spring配置文件(在resource中创建ApplicationContext.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">
4.配置所需资源(Service)为spring控制的资源(创建bean标签,id=接口的小名,class=实现接口类的所在目录)
<!-- 1.创建spring控制的资源,spring开始控制资源了
id最好是接口名第一个单词小写,可以任意取;后面的是实现类-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
</beans>
5.表现层(App)通过spring获取资源(Service实例)(通过ApplicationContext获得xml文件,然后通过接口获取getBean里的id就是接口小名,然后再获取其中实现类的方法)
public class UserApp {
public static void main(String[] args) {
//2.加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//3.获取资源,get自己定义的名字
UserService userService = (UserService) ctx.getBean("userService");
userService.save();
}
}
对bean标签的深入探讨
除了id和class属性外,还有name属性,用来给bean起多个别名,id我觉得取的名字不好 在App表现层获取:接口UserService 对象名userService = (UserService)ctx.getBean("userService或者userService1...")
bean标签的scope属性
1.单例对象:默认;
<bean id="userService" scope="singleton" class="com.itheima.service.impl.UserServiceImpl"/>
2.非单例对象:
<bean id="userService" scope="prototype" class="com.itheima.service.impl.UserServiceImpl"/>
Bean的生命周期
init和destroy方法都是在Impl实现类中创立的,也就是后面的class
<bean id="userService" scope="singleton" init-method="init"方法名 destory-method="destory"方法名 class="com.itheima.service.impl.UserServiceImpl"/>
init和是否单例有关系,单例模式init只走一次,非单例模式:创建一次,我走一次
Bean的工厂模式
静态工厂模式
创建一个工厂类:UserServiceFactory
public class UserServiceFactory{
public static UserService getService(){
return new UserServiceImpl();
}
}
<bean id="userService" class="com.itheima.service.UserServiceFactory" factory-method="getService"方法名/>
然后再去AplicationContext.xml文件中调用
实例工厂模式
public class UserServiceFactory2{
这里没有static了
public UserService getService(){
return new UserServiceImpl();
}
}
实例工厂对应的bean
<bean id="userService" class="com.itheima.service.UserServiceFactory2"/>
实例工厂创建bean,依赖工厂对象与对应的bean
<bean factory-bean="userService"和上方的id必须一致,问你工厂bean是哪一个 factory-method="getService"问你方法名>
DI:依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方法称为注入
set注入(主流)
创建DAO层 1.接口类
public interface UserDao(){
public void save();
}
2.创建该接口类的实现类
public class UserDaoImpl UserDao(){
public void save(){
System.out.println("userDaoImpl running")
}
}
3.在另一个实现类中使用
public calss UserServiceImpl UserService(){
1.定义变量
private UserDao userDao;
2.创建set,对需要进行注入的变量添加set方法
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void save(){
System.out.println("user service running...")
最后这里就可以使用userDao了
userDao.save();
}
}
4.去配置文件中声明
将要注入的资源(userDao需要被注入)声明为bean
<bean id="userDao" class="com.itheima.dao.Impl.UserDaoImpl"/>
<bean id = "userService" class = "com.itheima.service.impl.UserServiceImpl">
3.通过property属性进行注入
<property name="userDao"是set方法中后面那个名字的小写 ref="被注入的id号,也就是userDao"/>
</bean>
set注入,非引用类型
引入一个int型
private int num;
添加set方法
public void setNum(int num){
this.num = num;
}
不用再写bean标签了,他不是个资源
直接写注入,在哪引入的,id和class就是哪里,这里我省略了
<property name="num" value="123"/>
然后再我引入num的那个实现类,也就是UserServiceImpl中就可以引用了num
Sout(num) //123
构造器注入(了解)
在UserServiceImpl中,我想使用UserDao层的数据
private UserDao userDao;
private int num;
public UserServiceImpl(UserDao userDao,int num...){
this.userDao = userDao;
this.num = num;
}
在ApplicationContext.xml中
将要注入的资源(userDao需要被注入)声明为bean
<bean id="userDao" class="com.itheima.dao.Impl.UserDaoImpl"/>
<bean id = "userService" class = "com.itheima.service.impl.UserServiceImpl">
<constructor-arg name="userDao"ref="被注入的id号,也就是userDao"/>
<constructor-arg name="num" value="123456"/>
也可以在该标签里写 index,index的值就是传参的顺序
<bean/>
集合类型数据注入
在UserServiceImpl中调用BookDao中的数据
<--------------------------------->
private UserDao userdao
private BookDao bookdao
public void setBookDao(BookDao bookdao){
this.bookdao = bookdao;
}
public void setUserDao(UserDao userdao){
this.userdao = userdao;
}
<--------------------------------->
中间部分是我想调用这两个Dao,需要实现的写法
public void save(){
调用bookDao中里的save方法
bookDao.save();
}
在BookDaoImpl中
private ArrayList array;
public void setArray(ArrayList array){
this.array = array
}
在ApplicationContext.xml中配置
<bean id = "userDao"...>
我需要UserService可以用到userDao和BookDao的,实现写法
<bean id = "userService接口小名" class = "com.itheima.service.impl.UserServiceImpl">
<property name = "userDao是set方法中后面那个名字的小写" ref="对应被注入的的id号userDao"/>
<property name = "bookDao" ref="bookDao"/>
要想使用property,就得在此文件里写bean id对应的数据,如下:
</bean>
bookDao的set注入
<bean id = "bookDao"...>
<property name="arraylist">
<list>
<value>666</value>
</list>
</property>
<property name="properties">
<list>
<props>
<prop key="属性名">value值</prop>
</props>
</list>
</property>
<property name="arraylist">
<list>
<value>666</value>
</list>
</property>
<property name="array">
<array>
<value>666</value>
</array>
</property>
<property name="hashset">
<set>
<value>666</value>
</set>
</property>
<property name="hashset">
<map>
<entry key ="name" value="abcd"/>
</map>
</property>
<bean/>
使用p命名空间简化配置(了解)
1.需要在ApplicationContext.xml中 xmlns:xsi="..."的下面一行书写: xmlns:p="www.springframewrork.org/schema/p"
读取properties文件信息
1.在resources中创建 data.properties文件 书写 user:root pwd:123
2.在ApplicationContext.xml中配置 xmlns:context="www.springframework.org/schema/cont…"
-
加载配置文件 依然在xml中配置书写
<context:property-placeholder location="classpath:*.properties"/>
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
">
把所有的beans改成context
代码举例:
在Impl中书写
private String userName;
private String password;
然后创建set
public void setUserName(String userName){
this.userName=userName
}
在xml中
<bean id="userDao" class="...impl">
在这里使用data.properties文件中的数据
<property name="set的首字母小写userName" value="${user }"/>
</bean>
import导入配置文件
创建多个配置文件,将多个注入放在不同的文件里,最后import引入即可。
在主文件: <context:property-placeholder location="classpath:*.properties"/>
常用注解
启动注解功能 component
<context:component-scan base-package="packageName"/>
扫描itheima下面所有的包的注解,在ApplicationContext.xml中书写
例如:<context:component-scan base-package="com.itheima">
我想UserServiceImpl变成一个bean
@component("userService") 指定名称(bean-id),然后就可以在App中用userService调用方法
public class UserServiceImpl implements UserService{
...
}
之前是
<bean id = "userService接口小名" class = "com.itheima.service.impl.UserServiceImpl">
@component衍生的注解
和 @component一样的作用,但是区分了对应层
1.@Repository("userDao") 在Impl文件里用
2.@Controller
3.@Service
4.@Component
bean的作用域
在类的上方书写 @Scope,用来区分单例和多例。默认:singleton
bean的生命周期
@PostConstruct、@PreDestroy
bean的非引用类型属性注入
通过@Value,有了它,就可以省略set方法了,set方法诞生的目的就是为了给属性赋值
在Impl中
@Value("3")给num一个值为3
private int num;
@Value("abc")
private String version;
直接在该文件里使用
sout(num,version)
bean的引用类型属性注入(省略set)
在UserServiceImpl文件里
@Autowired
private UserDao userDao;
在UserDaoImpl中要书写
@Repository("userDao")
public void save(){...}
然后就可以直接在ServiceImpl里调用UserDaoImpl的数据
userDao.save();
注:书写一个UserDao类型的数据时,用Autowired可以自动匹配上;如果是多个UserDao类型的就会报错,需要指定
通过@Qualifier("userDao1");就是@Repository("名字");
名字要对应上;如果@Component没有写名字,默认用的就是所在类名
如果不知道具体先运行哪个
@Primary
加载properties文件中的属性
1.创建jdbc.properties文件
jdbc.userName=root123
jdbc.passWord=itheima
2.在需要使用的地方使用
@PropertySource("classpath:jdbc.properties")
public class BookImpl implements BookDao{
@Value("${jdbc.userName}")
private String userName;
}
3.直接疯狂输出
sout(userName)
纯注解格式配置
@Configuration:可以直接省略ApplicationContext.xml中的xml配置
@ComponentScan("base-package所在位置"):
我以前在里面配置过<context:component-scan base-package="..."/>
这个是用来解决注解的,但是我现在使用@ComponentScan就可以代替他了
这个时候就不需要再创建ApplicationContext.xml文件了 我创建一个SpringConfig文件,但是在App也就是main中要修改代码:
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = (UserService)ctx.getBean("userService");
userService.save();
bean加载控制
Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中;
@DependsOn:控制bean的加载顺序,使指定的bean加载完毕在加载其他的 配置在方法上,@DependsOn指定的bean优先于@Bean配置的bean进行加载 配置在类上
@Order:配置类注解,控制配置类的加载顺序
@Lazy:延迟加载,放在bean定义的位置