【仿牛客网笔记】初识Spring Boot,开发社区首页-Spring入门
这张图演示的IOC大概的原理,来源于官网手册,其中The Spring Container就是IOC容器,容器帮我们管理Bean的前提是具有两个条件,一是Bean的类型(Your Business Object(POJOS)),二是配置文件(Configuration Metadata)他们区别在于如果使用的是业务组件就用@Service注解,如果开发是一个出来请求的组件,就用@Controlle
一、Spring入门
1、Spring全家桶(大致分为四个方面)
Spring Framework: Spring 框架,是基石、是核心。
Spring Boot:利用SpringBoot构建项目,在这个项目基础上做Spring开发更容易,更方便。
Spring Cloud:做微服务的。当项目很大时,很难维护,我们可以用Spring Cloud分成若干个子项目,然后把他们集成在一起,但开发难度有所提高。
Spring Cloud Data Flow:Spring做数据集成的一个功能。当应用中有很多客户端,那么这些客户端所采集到数据心形态各异,通过Spring Cloud Data Flow将数据集成在一起,形成更有价值的数据。
本项目没有用到所有这四个,会用前两种。
Spring官网:
https://spring.io
二、Spring Framework Spring框架(分为四部分)
第一部分:Spring Core
包括IOC、AOP。IOC,AOP都是用来管理对象的一种思想。我们通常由Spring管理的对象叫做Bean,那么IOC、AOP管理的是Bean对象。IOC是一种面向对象的编程思想,AOP是一种面向切面的编程思想。总之,通过IOC和AOP可以管理一切Bean对象,比如第三方框架也可以拿来整合。
第二部分:Spring Data Access
Spring Data Access是Spring访问数据库的功能。我们会用到Transactions来管理事务、SpringMyBatis整合Mybits。
第三部分:Web Servlet
在Web开发是会用到Spring MVC。
第四部分:Integration(集成)
我们会在Integration(集成)中用Spring发邮件(Email)、定时任务(Scheduling)、消息队列(AMQP)、安全控制(Security)。
在Spring还有很多可以在官方手册中看到:https://spring.io/projects/spring-framework
需要先学好IOC,其他的功能才能容易学会
三、Spring IOC
1、IOC是一种缩写,全称为 Inversion of Control -控制反转、是一种面向对象编程的设计思想。
2、IOC通过Dependency Injection-依赖注入,是一种方式,是IOC思想的实现方式,通过依赖注入实现对bean对象管理是降低耦合度,便于维护。
3、Dependency Injection依赖注入的实现又基于IOC Container-IOC容器,是实现依赖注入的关键,本质上是一个工厂。
这张图演示的IOC大概的原理,来源于官网手册,其中The Spring Container就是IOC容器,容器帮我们管理Bean的前提是具有两个条件,一是Bean的类型(Your Business Object(POJOS)),二是配置文件(Configuration Metadata)
补充解释:
package com.Ring.community;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CommunityApplication {
public static void main(String[] args) {
SpringApplication.run(CommunityApplication.class, args);
}
}
SpringApplication.run(CommunityApplication.class, args); :Spring应用运行了,启动了Tomcat并且帮我们自动创建了Spring IOC容器。Spring容器创建后会自动的扫描Bean,将Bean装配到容器中。那些Bean会装配到容器。CommunityApplication.class类相当于配置文件,@SpringBootApplication 这是一个注解,这个注解标识了这个类,下图为@SpringBootApplication的底层。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
@SpringBootApplication 是由其他注解所组成的,
@SpringBootConfiguration表示这类是配置文件,
@EnableAutoConfiguration表示启动这个自动配置,
@ComponentScan表示逐渐扫描,能够自动扫描某些包下的Bean,实现自动装配Bean,它不是扫描全部的Bean,它会扫描配置类所在包以其子包下的Bean并且所在Bean上要有@Controller注解。
与@Controller注解等价的是@Service注解,@Service注解中有@Componment注解,在Bean上加上@Componment注解也可实现的。
* @see Repository
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
还有一个是@Repository注解,在@Repository注解中也有@Component注解。
* @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
他们区别在于如果使用的是业务组件就用@Service注解,如果开发是一个出来请求的组件,就用@Controller注解,如果开发的是一个数据库访问的组件就用@Repository,通用的就是@Component。
IOC容器的演示(在测试类test中进行):
我们在测试类中也希望用用到CommunityApplication这个配置类,则通过在测试类中添加@ContextConfiguration(classes=CommunityApplication.class)
那个类想实现Spring容器,则实现一个接口implements ApplicationContextAware
并显示该接口的方法setApplicationContext。
在实现方法setApplicationContext中传入了一个参数ApplicationContext,这个参数就是一个spring容器,它是一个接口,ApplicationContext继承于HierarchicalBeanFactory,HierarchicalBeanFactory继承于BeanFactory,BeanFactory就是Spring容器的顶层结构。ApplicationContext的功能更强一点,所以我们用ApplicationContext
然后我们添加了一个成员变量applicationContext,记录这个容器。
添加this.applicationContext=applicationContext;
编写一个测试方法,使用Spring容器
package com.Ring.community;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes=CommunityApplication.class)
public class CommunityApplicationTests implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
@Test
public void testApplication(){
System.out.println(applicationContext);
}
}
建一个包,专门访问数据库,包名为dao,在包中建立一个接口,接口中定义一些方法。
package com.Ring.community.dao;
public interface AlphaDao {
String select();
}
接口不能直接用,需要有一个接口的实现类。
package com.Ring.community.dao;
import org.springframework.stereotype.Repository;
@Repository("alphaHibernate")//自定义名为alphaHibernate,默认为类名小写,可以强制通过类名查找
public class AlphaDaoHibernateImpl implements AlphaDao {
@Override
public String select() {
return "Hibernate";
}
}
从容器中获取自动装配的Bean,getBean()方法是获取Bean,可以通过名字获取也可以通过类型获取,一般是通过类型或去,获取Bean后调用Bean中的select方法。结果我们成功的获取到了Bean并获得方法执行的 结果。
package com.Ring.community;
import com.Ring.community.dao.AlphaDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes=CommunityApplication.class)
public class CommunityApplicationTests implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
this.applicationContext=applicationContext;
}
@Test
public void testApplicationContext(){
System.out.println(applicationContext);
AlphaDao alphaDao=applicationContext.getBean(AlphaDao.class);
System.out.println(alphaDao.select());
}
}
这么做的好处的体现,我们再写一个Bean,体会它的优势。假设我们想将Hibenate替换为MyBatis,这个项目中我们可以这么做,在以上基础上我们在建立一个实现类AlphaDaoMyBatisImpl,我们只需要在需要的上面加上一个注解@Primary就可以。
package com.Ring.community.dao;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;
@Repository
@Primary//具有更高的优先级
public class AlphaDaoMyBatisImpl implements AlphaDao {
@Override
public String select() {
return "MyBatis";
}
}
可能会遇到这样一个问题,比如说我们想要还是需要Hibernate实现类,那如何得到呢?我们可以通过Bean的别名实现,首字母小写。
然后我们在CommunityApplicationtests中重新的获取Bean。
package com.Ring.community;
import com.Ring.community.dao.AlphaDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes=CommunityApplication.class)
public class CommunityApplicationTests implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException{
this.applicationContext=applicationContext;
}
@Test
public void testApplicationContext(){
System.out.println(applicationContext);
AlphaDao alphaDao=applicationContext.getBean(AlphaDao.class);
System.out.println(alphaDao.select());
alphaDao=applicationContext.getBean("alphaHibernate",AlphaDao.class);
System.out.println(alphaDao.select());//测试通过名字查找执行对应类
}
}
我们在新建一个Bean,我们需要业务组件会创建一个service包,然后我们新建一个AlphaService的类,添加@Service注解。然后添加init()方法,在该方法上加@PostConstruct注解,@POSTConstruct注解的意思这个方法会在构造器之后,为了便于观察我们可以加一个构造器AlphaService。然后添加一个destroy方法,在该方法中添加一个@PreDestroy注解,@PreDestroy注解是在销毁之前调用。
package com.Ring.community.service;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Service
//@Scope("prototype")
public class AlphaService {
public AlphaService(){
System.out.println("实例化AlphaService");
}
@PostConstruct
public void init(){
System.out.println("初始化AlphaService");
}
@PreDestroy
public void destory(){
System.out.println("销毁AlphaService");
}
}
写完以后测试一下,看看可不可以自动调用和销毁。Bean只能实例化一次,只销毁一次。然后我们在实例化一次会发现在程序的启动过程中只启动了一次,说明被Spring容器管理的Bean是单例的。
如果我们不想是单例的,可以是通过添加@Scope注解在AlphaService中,该注解默认是singlton单例,如果多个实例就是prototype,每次访问都会有一个实例,记得要注释掉。
有时候我们希望在容器中装配第三方Bean,我们只需要写一个配置类,然后在配置类中通过Bean声明来解决这个问题。新建一个Config包
,然后建一个配置类实例AlphaConfig
,并配置一个@Configration,
表示这个类是 一个配置类。然后定义第三方Bean,需要在方法中添加@Bean注解。
package com.Ring.community.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.SimpleDateFormat;
@Configuration
public class AlphaConfig {
@Bean
public SimpleDateFormat SimpleDateFormat(){
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
然后,我们再回到测试类中在编写一个测试方法。
@Test
public void testBeanConfig(){
SimpleDateFormat simpleDateFormat=
applicationContext.getBean(SimpleDateFormat.class);
System.out.println(simpleDateFormat.format(new Date()));
}
什么是依赖注入?注入的注解@Autowired加在一个成员变量上,意思是我希望spring容器注入到这个属性。同理获取AlphaService和SimpleDateFormat也是同样。
@Autowired
private AlphaDao alphaDao;
@Autowired
private AlphaService alphaService;
@Autowired
private SimpleDateFormat simpleDateFormat;
@Test
public void testDI(){
System.out.println(alphaDao);
System.out.println(alphaService);
System.out.println(simpleDateFormat);
}
我们在项目中实际开发如何使用这个思想,在开发中由Controller处理开发过程中的请求,会调用Service业务组件中的业务,然后业务组件会调用Dao,他们彼此之间相互依赖,因此它们可以通过依赖注入的方式来实现。
更多推荐
所有评论(0)