一、Spring是什么?
1.Spring是一个开源的优秀的轻量级的Java企业级应用框架;
2.Spring是一个容器框架,其中管理了很多对象,这些对象都被称为Bean;
3.Spring可以自动装配对象之间的依赖关系。
4.开发者无需考虑对象之间如何依赖,在开发过程中可以实现组件之间的低耦合。
5.Spring本身是一个低侵入式的框架。
6.Spring遵循面向接口的编程,避免对象之间直接耦合。
二、Spring的两项基本技术。
传统的方式:控制器对象要用业务类对象,业务类对象要用Dao对象。控制器内要写代码拿到业务类对象(new 一个业务对象),业务类对象也要通过某种方式创建Dao对象。这种方式是对象之间的依赖关系要通过对象自身维护。
1.IoC:控制反转,又称为DI(依赖注入),即对象间的依赖关系由自身维护改变为有外部容器给定。
过滤器:可以把通用的功能写在一处。这就是面向切面的编程思想。
2.AOP:面向切面的编程,将系统中多个模块都要用到的通用功能,不在各模块中调用了,而是剥离出来单独开发维护,在运行时由外部容器应用于各个模块中,这样的一种技术即AOP.
三、ApplicationContext对象:即Spring容器对象接口。
1.通过@Configuration注解的类说明容器配置;
2.在@Configuration注解的类中通过@Bean注解的方法说明受容器管理的bean对象,默认对象的名字便是方法名,也可以通过@Bean的name或者value参数指定名称。
3.ApplicationContext对象默认受管对象为单例模式、非懒加载(即容器启动就创建加载对象),可以配置实现对象的原型模式(prototype)和懒加载。
4.容器可以配置初始化方法和销毁方法。
5.仅单例模式才有非懒加载。原型模式对象不受容器管理、一律懒加载、不能被容器销毁。
四、Spring的使用
1.Spring的官网:https://docs.spring.io/spring/docs/5.2.2.RELEASE/spring-framework-reference/core.html#spring-core;
2.建一个maven项目,并在pom文件中引入jar包。(要用到的jar包:spring-context、log4j-core)
jar包在maven仓库中找:https://mvnrepository.com/
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ztt.spring</groupId>
<artifactId>spring_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring_demo</name>
<dependencies>
<!-- 引入spring容器包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- 引入log4j日志包 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
<!-- 引入编译器插件 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<!-- 编译级别 -->
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.配置log4j2.xml文件
log4j官网:https://logging.apache.org/log4j/2.x/ 拷贝配置信息
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="ztt.spring.*" level="trace" additivity="false">
<AppenderRef ref="Console" />
</Logger>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
案例场景:饲养员给动物喂食。饲养员依赖动物和食物。传统的方式是要new一个动物和食物,饲养员要是改换动物和食物的话,就得改代码,可维护性降低了。所以饲养员和动物食物应该是低耦合的。在Java中要让一个对象抽象化,不那么具体,就要用到接口。
1.食物接口,得到食物名称
package ztt.spring;
//食物接口
public interface Food {
//食物名称
public String getName();
}
2.动物接口,动物可以吃食物
package ztt.spring;
//动物接口
public interface Animal {
//动物吃食物
public void eat(Food food);
}
3.饲养员类,给动物喂食物,需要动物和食物。在Spring中,对象之间的依赖关系通过属性来依赖。属性提供set方法。
package ztt.spring;
//饲养员类
public class Feeder {
private Animal an;
private Food fd;
//工作
public void work() {
System.out.println("开始工作...");
an.eat(fd);
System.out.println("工作完成!");
}
public void setAn(Animal an) {
this.an = an;
}
public void setFd(Food fd) {
this.fd = fd;
}
}
4.实现类-猫实现了动物接口,鱼实现了食物接口。
package ztt.spring.impl;
import ztt.spring.Animal;
import ztt.spring.Food;
public class Cat implements Animal {
@Override
public void eat(Food food) {
System.out.println("猫吃:"+food.getName());
}
}
package ztt.spring.impl;
import ztt.spring.Food;
public class Fish implements Food {
@Override
public String getName() {
return "鱼";
}
}
以上对象还没有装配到一块,需要建立配置类。
5.配置类
package ztt.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import ztt.spring.impl.Cat;
import ztt.spring.impl.Fish;
import ztt.spring.impl.Mouse;
@Configuration//说明容器配置
public class AppConfig {
@Bean(name="myfeed")//受容器管理的一个bean,指定名字
@Autowired//自动装配,默认按照类型装配,即自动在容器中寻找符合类型的对象给参数赋值
public Feeder feeder( Animal an,Food fd) {
Feeder feeder=new Feeder();
feeder.setAn(an);
feeder.setFd(fd);
return feeder;
}
@Bean
public Cat cat() {
return new Cat();
}
@Bean
public Fish fish() {
return new Fish();
}
}
6.测试类
6.1需要创建容器对象,参数为配置类。
6.2从容器中获取对象,调取方法。
6.3运行。
package spring_demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import ztt.spring.AppConfig;
import ztt.spring.Feeder;
public class Test {
public static void main(String[] args) {
//需要创建容器对象,参数为配置类。
ApplicationContext ctx=
new AnnotationConfigApplicationContext(AppConfig.class);
//从容器中获取对象,调取方法。
Feeder feeder=ctx.getBean(Feeder.class);
feeder.work();
}
}
7.运行结果
新的问题:猫不吃鱼了,饲养员准备给他吃老鼠。
1.再来一个老鼠类,实现食物接口。
package ztt.spring.impl;
import ztt.spring.Food;
//老鼠类
public class Mouse implements Food {
@Override
public String getName() {
return "老鼠";
}
}
2.在配置类中,配置一个bean。
package ztt.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import ztt.spring.impl.Cat;
import ztt.spring.impl.Fish;
import ztt.spring.impl.Mouse;
@Configuration//说明容器配置
public class AppConfig {
@Bean(name="myfeed")//受容器管理的一个bean,指定名字
@Autowired//自动装配,默认按照类型装配,即自动在容器中寻找符合类型的对象给参数赋值
public Feeder feeder( Animal an,Food fd) {
Feeder feeder=new Feeder();
feeder.setAn(an);
feeder.setFd(fd);
return feeder;
}
@Bean
public Cat cat() {
return new Cat();
}
@Bean
public Fish fish() {
return new Fish();
}
}
3.运行会报错
11:34:05.898 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4ef782af
11:34:05.944 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
11:34:06.180 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
11:34:06.199 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
11:34:06.202 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
11:34:06.210 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'appConfig'
11:34:06.221 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myfeed'
11:34:06.230 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'cat'
11:34:06.262 [main] WARN org.springframework.context.annotation.AnnotationConfigApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myfeed' defined in ztt.spring.AppConfig: Unsatisfied dependency expressed through method 'feeder' parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'ztt.spring.Food' available: expected single matching bean but found 2: mouse,fish
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myfeed' defined in ztt.spring.AppConfig: Unsatisfied dependency expressed through method 'feeder' parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'ztt.spring.Food' available: expected single matching bean but found 2: mouse,fish
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:89)
at spring_demo.Test.main(Test.java:14)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'ztt.spring.Food' available: expected single matching bean but found 2: mouse,fish
at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1265)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 14 more
解决方法: 指定对象的优先装配@Primary加在方法名中或者在装配时在参数加注解@Qualifier("方法名")
package ztt.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import ztt.spring.impl.Cat;
import ztt.spring.impl.Fish;
import ztt.spring.impl.Mouse;
@Configuration//说明容器配置
public class AppConfig {
@Bean(name="myfeed")//受容器管理的一个bean,指定名字
@Autowired//自动装配,默认按照类型装配,即自动在容器中寻找符合类型的对象给参数赋值
public Feeder feeder(Animal an,@Qualifier("mouse") Food fd) {
Feeder feeder=new Feeder();
feeder.setAn(an);
feeder.setFd(fd);
return feeder;
}
@Primary//优先装配本对象
@Bean
public Mouse mouse() {
return new Mouse();
}
@Bean
public Cat cat() {
return new Cat();
}
@Bean
public Fish fish() {
return new Fish();
}
}
运行结果
实际开发中spring的配置:
1.在appConfig类中加两个注解
@Configuration
@ComponentScan("ztt.spring")//组件扫描,参数为要扫描的子包,必须和@Configuration一起使用
2.在各个类(Feeder,Cat,Fish,Mouse)中加注解
@Component//说明受spring管理的对象,名称默认为首字母小写的类名,可以指定名称
3.在Feeder属性上加自动装配注解@Autowired
4.在Feeder类中的食物属性上面指定@Qualifier("mouse") 或在食物类上面加@Primary,以上注解是为了保持单例模式,优先使用哪个就在哪上上面指定优先级。