Spring学习(上)

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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值