一、spring基础知识(一)

Spring框架是一个开源的Java平台,用于构建企业级应用程序和Java EE应用程序。它提供了许多功能和模块,使开发者能够更轻松地构建和管理复杂的应用程序。整个Spring框架的学习分成四个模块:IOC基础容器、AOP面向切面过程、Spring整合web环境、SpringMVC web层解决方案。

Spring Framework的技术栈,共分为五块,Testjunit测试类、Core容器、AOP层、数据接入、Web接入层。

Spring Framework的技术栈.png

先解释一下Spring的基础术语:

1、IoC(Inversion of Control,控制反转):

IoC是Spring框架的两大核心之一。它通过将对象的创建和依赖注入的控制权交给Spring容器来实现。开发者只需要定义依赖关系和配置,而不需要显式地管理对象的创建和销毁。那么,通俗的讲,什么是控制反转呐?就是中介。

假如你拥有一家公司,你需要雇佣一名保洁人员给你打扫卫生,那么你需要去管理这个保洁人员,负责给他开工资、处理他的五险一金、处理他的节假日福利等等,各种杂事,但如果你把它交给一个物业公司,那么,你只需要向物业公司提出你的需求,其余的事情都交给他去处理就可以了,IoC就是这个作用。之所以叫控制反转,是因为正常是你去雇佣保洁,主动去做这个事。但是现在是让物业公司去做,再把保洁安置到你的公司,对于保洁的控制权从你的手里,转移到物业公司,所以叫控制反转。那么保洁人员安置到你公司的这个动作,就叫做依赖注入,所以有IoC的地方,就会提到依赖注入。

2、DI(Dependency Injection,依赖注入):

DI是IoC的一种具体实现方式,它是Spring框架的另一个核心概念。通过依赖注入,Spring容器可以在对象创建时自动将其依赖的其他对象注入到该对象中,降低了对象之间的耦合性,使得代码更加灵活和可维护。

盗一张别人的图,觉得这个齿轮图,很好的展现了IOC解耦的一个作用。

IoC解耦前.png
IoC解耦后.png
3、BeanFactory:

bean工厂,去生成、管理Bean对象的,是IoC的核心接口,就是通过这个接口,去实现反转、注入的。以下是BeanFactory的开发步骤:

BeanFactory的开发步骤.png
<!--pom文件导入spring核心包-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.3.7</version>
</dependency>
/**
 * 新建一个service、一个实现类
 **/
public interface UserService {}
public class UserServiceImpl implements UserService {}
<!--创建beans.xml配置文件,放到resources目录下-->
<bean id="userService" class="com.dj.service.impl.UserServiceImpl"></bean>
import com.dj.dao.UserDao;
import com.dj.service.UserService;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * 创建测试类,获取beanFactory创建的bean对象
 **/
public class BeanFactoryTest {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions("beans.xml");
        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);
    }
}
4、ApplicationContext:

ApplicationContext由BeanFactory派生而来,除了生成bean对象,也包含事件发布、国际化消息资源包等,父类共6个接口。在IDEA中(使用windows的快捷键),选中要查看的对象,右键show diagram,可以查看当前对象有哪些父类接口。

ApplicationContext父类接口.png

在IDEA中(使用windows的快捷键),选中要查看的对象,使用Ctrl+H的快捷键,可以查看类的继承关系。

ApplicationContext类的继承关系.png
import com.dj.dao.UserDao;
import com.dj.service.UserService;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

/**
 * 创建测试类,获取beanFactory创建的bean对象
 **/
import com.dj.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println(userService);
    }
}

BeanFactory和ApplicationContext都能生成bean对象,但是生成的时机是不一样的。BeanFactory是在获取bean对象时才能获取,而ApplicaitonContext是在类加载的时候就已经生成了。

5、关于bean的常用属性

id、class、name、scope、lazy-init、init-method、autowire、factory-bean、factory-method
1)关于id,通过配置bean的id名称,修改beanName,重要

<bean id="userService" class="com.dj.service.impl.UserServiceImpl"></bean>

//如果不配置id,beanName为com.dj.service.impl.UserServiceImpl
UserService userService = (UserService) context.getBean("com.dj.service.impl.UserServiceImpl");

2)关于name,配置别名,可以配置多个别名aa、bb、cc,几乎不用,不重要

<bean id="userService" name="aa,bb,cc" class="com.dj.service.impl.UserServiceImpl"></bean>

UserService aa= (UserService) context.getBean("aa");
UserService bb= (UserService) context.getBean("bb");

debug模式,查看context,context->beanFactory->aliasMap

bean配置别名.png

3)关于scope,如果是单纯的spring环境,属性有singleton、prototype,默认是singleton,即使实例化多个对象,对象地址都是同一个,一般只用默认的。
当scope是prototype,每次实例化,每次都是新的对象。
如果添加spring-webmvc、spring-web环境时,scope属性还有request、session。
不重要。

<bean id="userService" class="com.dj.service.impl.UserServiceImpl" scope="prototype"></bean>

UserService userService1= (UserService) context.getBean("userService");
UserService userService2= (UserService) context.getBean("userService");

4)关于lazy-init,先不创建,谁用谁创建,对于beanFactory无效,ApplicationContext有效

<bean id="userService" class="com.dj.service.impl.UserServiceImpl" lazy-init="true"></bean>

5)关于init-method、destroy-method(用不到),初始化方法是指定对象构造完毕后,默认执行的、销毁方法是指容器关闭后,需要显示的调用容器关闭方法,才会默认执行该方法。

<!--在service实现类中添加方法名为init、destroy的方法,此处省略-->
<bean id="userService" class="com.dj.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy"></bean>

此处,还可以提到InitializingBean接口,利用它的afterPropertiesSet方法执行赋值

package com.dj.service.impl;

import com.dj.service.UserService;
import org.springframework.beans.factory.InitializingBean;

public class UserServiceImpl implements UserService, InitializingBean {

    public UserServiceImpl(){
        System.out.println("构造方法:UserServiceImpl ...");
    }

    public void init(){
        System.out.println("对象初始化后执行的方法:init ...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("对象初始化完成后的属性操作:afterPropertiesSet ...");
    }
}

import com.dj.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println(userService);
    }
}

/** 控制台打印的结果如下,由此可看出各方法执行的顺序:
 *  构造方法:UserServiceImpl ...
 *  对象初始化完成后的属性操作:afterPropertiesSet ...
 *  对象初始化后执行的方法:init ...
 *  com.dj.service.impl.UserServiceImpl@478190fc
 **/

6)关于spring实例化bean的两种方式:构造方法、工厂方法。spring的实例化底层都是通过BeanFactory来实现的,所以工厂方法就是两层工厂方法的嵌套,默认就是无参构造器。

package com.dj.dao;

public interface UserDao {

}


package com.dj.dao.impl;

import com.dj.dao.UserDao;

public class UserDaoImpl implements UserDao {

}


package com.dj.service.impl;

import com.dj.dao.UserDao;
import com.dj.service.UserService;

public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserServiceImpl(){
        System.out.println("无参构造方法:UserServiceImpl ...");
    }

    public UserServiceImpl(String name){
        System.out.println("有参构造方法:UserServiceImpl ...");
    }
}

<!--配置constructor-arg参数时,就调用有参构造方法,不配置,就调用无参构造方法-->
<bean id="userService" class="com.dj.service.impl.UserServiceImpl">
    <constructor-arg name="name" value="dj"></constructor-arg>
    <property name="userDao" ref="userDao"/>
</bean>

工厂方法又分为三种:静态工厂方法、实例工厂方法、实现FactoryBean规范延迟实例化bean。
静态工厂方法,直接用类名调用静态方法即可:

/**
 * 新建工厂类
 */
package com.dj.service.impl;

public class UserDaoFactory1 {
    public static UserDaoImpl getUserDaoBean() {
        //通过此方法实例化对象,方便进行其它的逻辑处理
        return new UserDaoImpl();
    }
}

<bean id="userDao1" class="com.dj.service.impl.UserDaoFactory1" factory-method="getUserDaoBean"></bean>

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object object = context.getBean("userDao1");
        System.out.println(object);
    }
}

实例工厂方法,先获取工厂bean,再调用实例化方法:

package com.dj.service.impl;

import com.dj.dao.impl.UserDaoImpl;

/**
 * 新建工厂类
 */
public class UserDaoFactory2 {
    public UserDaoImpl getUserDaoBean() {
        return new UserDaoImpl();
    }

}

<bean id="userDaoFactory2" class="com.dj.service.impl.UserDaoFactory2"></bean>

<bean id="userDao2" factory-bean="userDaoFactory2" factory-method="getUserDaoBean"></bean>

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object object = context.getBean("userDao2");
        System.out.println(object);
    }
}

实现FactoryBean规范延迟实例化bean,通过实现FactoryBean接口来实现,:

package com.dj.factory;

import com.dj.dao.UserDao;
import com.dj.dao.impl.UserDaoImpl;
import org.springframework.beans.factory.FactoryBean;

/**
 * 新建工厂类
 */
public class UserDaoFactory3 implements FactoryBean<UserDao> {

    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

<bean id="userDao3" class="com.dj.factory.UserDaoFactory3"></bean>

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Object object = context.getBean("userDao3");
        System.out.println(object);
    }
}

7)bean的依赖注入配置:通过set方法,构造器的方法。其中,ref是reference,参考、引用的意思。

  • set方法:
<property name="name" value="dj">
<property name="userDao" ref="userDao">     
  • 构造器方法
<constructor-arg name="name" value="dj"></constructor-arg>
<constructor-arg name="userDao" ref="userDao"></constructor-arg>

依赖注入的类型共三类:普通型、引用型、集合数据类型。此处仅演示集合类型,List、Set、Properties。

package com.dj.service.impl;

import com.dj.dao.UserDao;
import com.dj.service.UserService;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class UserServiceImpl implements UserService {
    private List<String> stringList;
    private List<UserDao> userDaoList;

    private Set<String> stringSet;

    private Map<String,String> stringMap;

    private Properties properties;

    public void setStringList(List<String> stringList) {
        this.stringList = stringList;
    }

    public void setUserDaoList(List<UserDao> userDaoList) {
        this.userDaoList = userDaoList;
    }

    public void setStringSet(Set<String> stringSet) {
        this.stringSet = stringSet;
    }

    public void setStringMap(Map<String,String> stringMap) {
        this.stringMap = stringMap;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void show(){
        System.out.println(stringList);
        System.out.println(userDaoList);
        System.out.println(stringSet);
        System.out.println(stringMap);
        System.out.println(properties);
    }
}

<bean id="userService" class="com.dj.service.impl.UserServiceImpl">
    <property name="stringList">
        <list>
            <value>aaa</value>
            <value>bbb</value>
            <value>ccc</value>
        </list>
    </property>
    <property name="userDaoList">
        <list>
            <ref bean="userDao"></ref>
            <ref bean="userDao1"></ref>
            <ref bean="userDao2"></ref>
        </list>
    </property>
    <property name="stringSet">
        <set>
            <value>111</value>
            <value>222</value>
            <value>333</value>
        </set>
    </property>
    <property name="stringMap">
        <map>
            <entry key="a" value="1"></entry>
            <entry key="b" value="2"></entry>
            <entry key="c" value="3"></entry>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="1">a</prop>
            <prop key="2">b</prop>
            <prop key="3">c</prop>
        </props>
    </property>
</bean>

import com.dj.service.UserService;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;

public class BeanFactoryTest {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        xmlBeanDefinitionReader.loadBeanDefinitions("beans.xml");
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.show();
    }
}

关于自动装配,用byName居多,一般不会重复。name是根据set方法的名字来匹配的,setUserDao()方法名中,去set,小写首字母,得到userDao,要与xml文件中的bean的id相匹配,才可实现自动装配。

<bean id="userService" class="com.dj.service.impl.UserServiceImpl" autowire="byName"/>
<bean id="userDao" class="com.dj.dao.impl.UserDaoImpl"></bean>


package com.dj.service.impl;

import com.dj.dao.UserDao;
import com.dj.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

8)spring的xml标签,大体上分为两类:默认标签、自定义标签。默认标签是可以直接使用的,不需要额外导入的,如beans。自定义标签就是需要额外引入其它命名空间,并且通过前缀来引用的。

<?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/beans/spring-context.xsd">
    <!--通过前缀,来引用命名空间-->
    <context:property-placeholder></context:property-placeholder>
</beans>

spring默认的命名空间下,默认的标签,共4种:

  • beans:xml的根标签,一个xml也可以有多套beans,但是不会用到。也可以用profile属性来切换不同的环境。
    beans是默认生成的根标签,多套beans标签也是放在根标签里面的。如果新增<beans>标签,它是要加在最下面的,不然会让之前添加的<bean>找不到根。
<?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/beans/spring-context.xsd">

    <bean id="userDao2" factory-bean="userDaoFactory2" factory-method="getUserDaoBean"></bean>

    <bean id="userDao3" class="com.dj.factory.UserDaoFactory3"></bean>

    <beans profile="test">
        <bean id="userService" class="com.dj.service.impl.UserServiceImpl"/>
    </beans>
</beans>

那么如何告诉程序,我现在需要用test环境,而不是默认的环境呐?在主程序中设置环境变量、或者在vm启动参数添加也可以。

//放在main方法中
System.setProperty("spring.profiles.active","test");

//vm options添加此环境变量
-Dspring.profiles.active=test

指定test环境时,除test标签内的环境变量会生效,根默认的配置也会生效。

  • bean:beans的子标签,这个就不详细说了,一直在用。
  • import:外部配置导入的标签。项目比较大的时候,可能会根据业务拆分成模块的配置文件,此时就需要import来将其它配置添加到主配置文件中。在resources资源目录下添加xml文件,userBeans.xml。
<!--在beans根目录下,添加import标签-->
<import resource="userBeans.xml"></import>
  • alias:指定bean的别名,使用较少,算了,不写了,就这样吧。
<!--在beans根目录下,添加alias标签-->
<alias name="userDao" alias="xxxx"></alias>

9)spring获取bean的方法:

  • public Object getBean(String name);常用
  • public <T> T getBean(String name, Class<T> requiredType);
  • public <T> T getBean(Class<T> requiredType);常用,且<bean>的返回类型只能有一种
UserService userService1 = (UserService) beanFactory.getBean("userService");
UserService userService2 = beanFactory.getBean("userService", UserService.class);
UserService userService3 = beanFactory.getBean(UserService.class);

10)spring引入非自定义bean(druid、mysql),二者没有什么强相关性,可独立使用,具体druid和mysql的关系,百度吧。

<!--pom文件中导入坐标-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.23</version>
</dependency>
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

<!--beans.xml文件中添加Druid的实例化信息-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>

<!--beans.xml文件中添加mysql的实例化信息,具体查询一下mysql的实例化方法就行-->
<bean id="driver" class="java.lang.Class" factory-method="forName">
    <constructor-arg name="className" value="com.mysql.jdbc.Driver"></constructor-arg>
</bean>

<bean id="connection" class="java.sql.DriverManager" factory-method="getConnection" scope="prototype">
    <constructor-arg name="url" value="jdbc:mysql://localhost:3306"></constructor-arg>
    <constructor-arg name="user" value="root"></constructor-arg>
    <constructor-arg name="password" value="root"></constructor-arg>
</bean>

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        System.out.println(context.getBean("dataSource"));
        System.out.println(context.getBean("connection"));
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容

  • Spring简介 spring框架由Rod Johnson开发,2004年发布了Spring框架的第一版。Spri...
    qiuqiu_hz阅读 1,077评论 0 15
  • Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB...
    OSET我要编程阅读 2,708评论 0 3
  • 来源:公众号 作者:Java知音链接:https://mp.weixin.qq.com/s/45yy2qNIAI...
    小郭子阅读 620评论 0 0
  • 参考W3C Spring教程 Spring致力于J2EE应用的各种解决方案,而不仅仅专注于某一层解决方案。可以说S...
    王侦阅读 1,172评论 0 6
  • 如下是整篇文章的结构,所需阅读时间大约20min Spring简介 Spring框架由Rod Johnson开发,...
    李序锴阅读 897评论 0 15