文章目录
Spring学习(上)
专题一:idea下maven项目的创建与运行
普通java工程(非web环境,se)
(1)全局配置:font,file encodings
(2 ) maven根路径,xml路径,local repository
(3) appearance
创建新的工程–勾选Create from archetype–选择quickstart
指定基本坐标:groupid–artifact–version
如:com.hxh–java01–1.0-SNAPSHOT
启用自动导入–property修改为1.8,单元测试最低版本4.12
编写源代码,默认提供App类,可直接运行。
maven项目里的几个重要目录:
src/main/java 存放源代码文件
src/main/resources 存放资源配置文件
src/test/java 存放单元测试源文件
src/test/resources 存放测试资源源文件
pom.xml 坐标 || 插件 || 打包配置 || 聚合依赖标签
创建目录:
首先认识几个图标:project Structure – modules --sources
蓝色sources存放源代码,源代码里不能写单元测试代码
绿色tests存放单元测试代码,里面不可以写main方法。
resources存放资源文件,右击右键mark as resources。
excluded 比如target目录,编译输出的目录,比如lifecycle–compile–>target
查看项目依赖准确去看的方式是:project structure–modules–dependencies
如何引入新的依赖:
比如mysql,去maven在在线仓库搜索:
百度输入mvnrepo:
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency>
左侧可以看到有哪些类,具体类里面有哪些函数,可以再点击structure来查看。
web项目
file–project–new
类型选择webapp
修改properties中1.8环境–单元测试4.12 坐标添加以及目录创建同普通项目。main下面创建java目录与resources目录。
web项目的部署:
方法一:外部的tomcat。
通过add configuration–template–tomcat server local
1,先配置本地的tomcat目录(add - )
2,配置待部署的项目 add configuration–加号–修改Name与端口号–
点击deployment–右边的artifact–选择:war exploded,修改application context要访问项目的名称(自己指定)。
依赖是项目打包后运行必须的,而插件是程序的应用扩展,项目打包是不需要这些插件的,开发的时候是需要的。
方法二:通过插件。
(1)可以通过引入build标签下的plugins,使用jetty。jetty-maven-plugin 9.4.21.
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.21.v20190926</version>
</dependency>
配置一个启动插件的命令,基于maven,mvn jetty:run。
(2)tomcat插件 搜索tomcat,左侧选择maven plugin
tomcat7-maven-plugin 2.1 tomcat7:run
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat7-maven-plugin -->
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
</dependency>
聚合工程
掘金/码云
多模块场景–电商
后台管理(商家后台)
门户网站
购物车
搜索模块
子模块的jetty:jetty:run -Djetty.port=8081
1,新建工程–建立一个父模块(不勾选archetype)
2,选中工程右键新建–module–选对应的archetype
3,主模块的src基本不会使用,可以删去。
项目部署:jetty插件
如果有公共代码供其他模块调用,可以将公共代码独立为一个模块,设置为普通工程server模块,提供商品详情查询方法实现。
后台管理模块调用server商品查询service(后台管理引入server坐标依赖),(dao实现访问service)在servlet里编写调用代码。
admin的pom里引入servlet坐标且在后台main文件夹里面新增一个java文件夹,标记为源码,新增一个GoodsController.java,
//配置一个servlet,使用注解代替web.xml
@WebServlet(urlPatterns = "/goods")
public class GoodsController extends HttpServlet{
//使用goodsservice
private GoodsService goodsService = new GoodsService();
//重写service
@override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
String gid = req.getParameter("gid");
Goods goods = goodsService.queryGoodsByGoodsId(Integer.parseInt(gid));
System.out.println(goods);
}
}
启动父子模块,首先要安装,新增一个add的install,启动admin:
working directory为父模块地址
commandline 命令为: clean compile install -Dmaven.test.skip = true 意思是先把这些代码以java文件或者war包安装到本地,跳过单元测试。
访问域名为:localhost:8081/goods?gid=1
专题二:ioc对象实例化
ioc扫描器配置与应用
扫描器只对扫描包范围下的对象进行扫描:
<?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">
<!--
引入扫描器 base-package为扫描范围
并不会全部实例化,需使用注解@Repository(注解在类级别上)
-->
<context:component-scan base-package="org.example"/>
</beans>
几个注解:(作用在类级别)
@Repository:作用在持久层(dao)上。
@Service:业务层,作用在服务层
@Controller:作用在控制层 || 视图层
@Component:非上面几层时用,组件。
扫描器环境下是可以实现装配的,上面的@Resource与@Autowired是可以用的。
@Repository
public class Which {
@Resource
private UserService userService;
public void test(){
userService.test();
System.out.println(StringUtils.isBlank(" "));
}
}
@Service
public class UserService {
public void test(){
String aa = " hello spring ";
System.out.println(" hello spring ");
System.out.println(aa.length());
System.out.println(aa.trim().length());
}
}
一种Apache开源封装DbUtils----jdbc的工具,可以用于dao层的持久层,如果项目较小使用这个。
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
ioc作用域&生命周期
从spring容器中拿到的对象均为单例的,对于bean的作用域类型如下:
spring容器中有单例缓存池。
<bean id="userService" class="org.example.service.UserService" lazy-init="true"/>
lazy-init默认为false,即spring容器启动的时候直接实例化(在空构造器里写代码测试)。如果修改为true,则代表容器启动时候并不会实例化,只有去取用该对象时候才实例化。
lazy-init懒加载,默认为false的作用有两点:
1、提前发现应用程序潜在的问题
ioc启动时候对bean对象进行实例化,如果对象实例化出现问题,可以及时发现与解决。
2、提高应用程序执行的性能
省略掉实例化时间的开销。
Ioc管理的对象均为单例对象,什么样的对象适合做单例?
对象有:
dao service web|controller 适合
po | model 不适合 对象会改变(属性值会发生变化)成员变量值(属性值)发生改变(多线程)
对象状态有可能发生改变–有状态bean
util 适合
filter | listener 适合
对于多线程来说,单例class要考虑实例化一次时,多个线程都取用同一个成员变量。
多个成员定义在方法里成为局部变量。
prototype作用域:
scope默认是单例的:
<bean id="userService" class="org.example.service.UserService" scope="prototype"/>
scope为单例的时候才缓存到单例缓存池,为prototype时不缓存,每次创建都是一个新的对象。
Bean的生命周期:定义–>实例化–>初始化–>使用–>销毁
初始化方法:1,通过xml中指定init-method属性来完成。
2,实现org.Springframework.beans.factory.InitializingBean接口
<context:annotation-config/>
<bean id="which" class="org.example.Dto.Which" lazy-init="default" init-method="init" destroy-method="destroy"/>
<bean id="userService" class="org.example.service.UserService"/>
@Repository
public class Which {
@Resource
private UserService userService;
public void test(){
userService.test();
System.out.println(StringUtils.isBlank(" "));
}
public Which() {
System.out.println("进行了实例化。。。");
}
public void init(){
System.out.println("运行初始化方法。。。");
}
public void destroy(){
System.out.println("启动了销毁bean的方法。。。");
}
}
@Test
public void test09(){
AbstractApplicationContext af = new ClassPathXmlApplicationContext("spring.xml");
Which which = (Which) af.getBean("which");
which.test();
af.close();
}
进行了实例化。。。
运行初始化方法。。。
hello spring
17
12
true
二月 24, 2021 6:31:20 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@5d3411d: startup date [Wed Feb 24 18:31:19 CST 2021]; root of context hierarchy
启动了销毁bean的方法。。。
集合注入
集合大概分为四种类型:list,set,map,property。
集合注入使用set注入。
一:list(三种打印)
<bean id="userService" class="org.example.service.UserService">
<property name="users" >
<list>
<value>lancer</value>
<value>archer</value>
<value>saber</value>
<value>assassin</value>
</list>
</property>
</bean>
@Service
public class UserService {
private List<String> users;
public void setUsers(List<String> users) {
this.users = users;
}
public void test(){
String aa = " hello spring ";
System.out.println(aa.trim());
//无需流的遍历
users.forEach(System.out::println);
System.out.println("*********");
//增强for循环遍历
for(String ele:users){
System.out.println(ele);
}
System.out.println("*********");
//匿名内部实现
users.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
@Test
public void test01()
{
BeanFactory ac = new ClassPathXmlApplicationContext("spring02.xml");
UserService userService1 = (UserService)ac.getBean("userService");
userService1.test();
}
hello spring
lancer
archer
saber
assassin
*********
lancer
archer
saber
assassin
*********
lancer
archer
saber
assassin
二:set同list
三:map(四种打印)
<property name="map">
<map>
<entry>
<key><value>han</value></key>
<value>xiaohan</value>
</entry>
<entry>
<key><value>liu</value></key>
<value>bei</value>
</entry>
<entry>
<key><value>cheng</value></key>
<value>yi</value>
</entry>
</map>
</property>
@Service
public class UserService {
private Map<String,String> map;
public void setMap(Map<String, String> map) {
this.map = map;
}
public void test(){
String aa = " hello spring ";
System.out.println(aa.trim());
//使用lambda遍历
map.forEach((key,value)-> System.out.println(key+"-->"+value));
System.out.println("#############");
//匿名内部类实现
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String s, String s2) {
System.out.println(s+"-->"+s2);
}
});
System.out.println("#############");
//使用entry遍历map
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey()+"-->"+entry.getValue());
}
System.out.println("#############");
//使用keyset遍历map
for(String str:map.keySet()){
System.out.println(str+"-->"+map.get(str));
}
}
}
四:properties
<property name="properties">
<props>
<prop key="han">xiaohan</prop>
<prop key="liu">bei</prop>
<prop key="cheng">yi</prop>
</props>
</property>
@Service
public class UserService {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void test(){
String aa = " hello spring ";
System.out.println(aa.trim());
//使用lambda遍历
properties.forEach((key,value)-> System.out.println(key+"-->"+value));
}
}
自动注入
准备工作:
1,加入spring-aop jar包 spring-aop-5.0.8.RELEASE.jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
上文的依赖已经自动加载了aop。
2,xml配置:加入context命名空间与xsd地址
xmlns:context=“http://www.springframework.org/schema/context”
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
3,添加<context:annotation-config/>配置
最终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:annotation-config/>
<!--
id:bean对象唯一标识
class:业务对象的全路径
-->
<bean id="which" class="org.example.Dto.Which"></bean>
<bean id="userService" class="org.example.service.UserService"></bean>
</beans>
两种注解:省略property标签的编写
1:@Resource
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
声明类别:类级别(类与接口),属性级别,方法级别 常用在属性与方法(set方法)
装配规则:默认按照属性名称装配,如果查不到xml中的属性名(id),使用类型(class类型)实现装配如果显式声明Resource的name与value值,内部装配按照value执行装配,如果存在该value对应的对象,装配成功,不存在则装配失败。
为什么使用name?因为对于装配接口的多个实现时有用。如果只配置了一个实现,则不需要配置name。
@Resource
private UserService userService;
//或者在set方法上
@Resource
public void setUserService(UserService userService) {
this.userService = userService;
}
//name显式声明注入属性名
@Resource(name="userService")
private UserService userService;
2:@Autowired
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
声明级别:常用 属性级别(推荐) 构造器 set方法
装配规则:默认按照class类型去装配
如果想达到跟@Resource同样的功能,则配合@Qualifier同时使用。
@Autowired
private UserService userService;
@Autowired
@Qualifier(value="userService")
private UserService userService;
注解的实现是通过反射,首先通过反射获得属性,通过It.getClass().getDeclaredField() 然后通过Field的set方法。
field.setAccessible(true); |
public class Which {
@Autowired
@Qualifier(value="userService")
private UserService userService;
public void test(){
userService.test();
}
}
@Test
public void test09(){
BeanFactory af = new ClassPathXmlApplicationContext("spring.xml");
Which which = (Which) af.getBean("which");
which.test();
}
手动注入
1:多文件加载
内部bean对象实例化的几种方式:
1,通过构造器
解析xml–提取bean标签–通过反射 调用构造器(空构造或带参(带参通过属性赋值的操作))创建实例。
2,工厂形式实现实例化(静态工厂与实例化工厂)
静态工厂与实例化工厂示例:
(1)建一个对象
public class AccountService {
public void test(){
System.out.println("AccountService.test.....");
}
}
(2)建一个静态工厂(里面方法是静态的)& 实例化工厂
public class StaticFactory {
public static AccountService getAccountService(){
return new AccountService();
}
}
public class InstanceFactory {
public AccountService getAccountService(){
return new AccountService();
}
}
(3)spring.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">
<!--
1,默认构造器实例化
id:bean对象唯一标识
class:业务对象的全路径
-->
<bean id="userService" class="org.example.service.UserService"></bean>
<!--
2,静态工厂实例化
id:bean的唯一标识
class:替换为静态工厂的全路径
factory-method:产生accountService的静态方法名
-->
<bean id="accountService" class="org.example.factory.StaticFactory" factory-method="getAccountService"></bean>
<!--
3,实例化工厂实例化
实例化工厂bean class:实例化工厂的全路径
factory-bean 引用实例化工厂 再指定实例化工厂的方法
-->
<bean id="instanceFactory" class="org.example.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
</beans>
(4)测试
@Test
public void test02()
{
BeanFactory ac = new ClassPathXmlApplicationContext("spring02.xml");
AccountService accountService = (AccountService)ac.getBean("accountService");
accountService.test();
System.out.println(ac.isSingleton("accountService"));
}
//多文件xml加载
@Test
public void test04()
{
BeanFactory ac = new ClassPathXmlApplicationContext("spring.xml","spring02.xml");
AccountService accountService = (AccountService)ac.getBean("accountService");
accountService.test();
System.out.println(ac.isSingleton("accountService"));
UserService userService = (UserService) ac.getBean("userService");
userService.test();
System.out.println(ac.isSingleton("userService"));
结果为:
多文件加载两种方式:
1:可以分开几个xml
2:可以建一个总的xml,在xml中使用import标签:
<?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="spring.xml"></import>
<import resource="spring02.xml"></import>
</beans>
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","spring02.xml");
BeanFactory ac = new ClassPathXmlApplicationContext("all.xml");
2:ioc对象依赖注入☞Set注入
首先看一下两种使用别处对象的问题:
//方法一
public class Which {
private UserService userService = new UserService();
}
//方法二
class One {
private UserService userService;
public One(UserService userService){
this.userService = userService;
}
}
角度一:方法一不太好,本身不是单例,增大内存开销。方法二外部传入,可以以单例方式传进来。高并发时废掉了。
角度二:方法一写死了实例化哪个对象,对于多态来说没有灵活性。如果方法二private定义了一个接口,那传入哪个子类都没问题。
依赖注入就是指:给属值赋值
ioc对象依赖注入的四种形式:
1:Set注入(通过set方法实现属性赋值)
2:构造器(借助带参构造)
3:静态工厂
4:实例化工厂
一:set注入
public class Which {
private UserService userService;
//必须提供set方法,get视情况而定
public void setUserService(UserService userService) {
this.userService = userService;
}
public void test(){
userService.test();
}
}
<?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">
<!--
id:bean对象唯一标识
class:业务对象的全路径
-->
<bean id="which" class="org.example.Dto.Which">
<!--
set注入 property配置
name:业务类中属性名
ref:引用的某个bean标识
-->
<property name="userService" ref="userService"></property>
</bean>
<bean id="userService" class="org.example.service.UserService"></bean>
</beans>
@Test
public void test09(){
BeanFactory af = new ClassPathXmlApplicationContext("spring.xml");
Which which = (Which) af.getBean("which");
which.test();
}
综上,对于接口,也可以,外部传入的待定,在xml中配置实现类的bean,ref不同的实现类。
对于字符串而不是类类型的属性,直接对property使用“value”。
1,给属性提供set方法
2,配置bean的property子标签
业务对象:
name:属性名
ref:业务对象的引用 id标识
具体value(string,integer,double,boolen)除了string,其他的value为"value",都可以直接强转类型。
name:属性名
value:具体值
3:ioc对象依赖注入☞构造器&工厂注入
构造器注入(带参构造器)
public class Which {
private UserService userService;
//带参构造器注入
public Which(UserService userService) {
this.userService = userService;
}
public void test(){
userService.test();
}
}
<bean id="which" class="org.example.Dto.Which">
<constructor-arg name="userService" ref="userService"></constructor-arg>
<constructor-arg name="userName" value="bell"></constructor-arg>
<constructor-arg index="1" ref="userService"></constructor-arg>
</bean>
<bean id="userService" class="org.example.service.UserService"></bean>
xml文件的约束为xsd(http本地文件),通过schema或者dtd规范来定义。
mybatis使用dtd来约束。
构造器里面面临的问题:构造器注入的循环引用问题,需要使用set注入来解决。
因为双方都有默认构造器,都可以自身实例化,自身实例化之后
再调用的set方法去注入,所以不会影响。
了解内容:
工厂注入:(实际上还是借助set注入)要注入的对象是由静态工厂产生的:
<!--
实例化工厂
-->
<bean id="instanceFactory" class="org.example.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factory-method="getUserServiceService"></bean>
<!--
静态工厂
-->
<bean id="userService1" class="org.example.factory.StaticFactory" factory-method="getUserService"></bean>
<bean id="which" class="org.example.Dto.Which">
<property name="userService" ref="userService"></property>
<property name="userService1" ref="userService"></property>
</bean>