JavaConfig出现历史
Spring1.x 时代
通过xml文件配置bean,随着项目的不断扩大,需要将xml配置分放到不同的配置文件中,需要频繁的在java类和xml配置文件中切换;但是,Spring的依赖注入与声明式事务意味着组件之间再也不存在紧耦合,再也不用重量级的EJB了。
Spring2.x 时代
随着JDK 1.5带来的注解支持,Spring2.x可以使用注解对Bean进行申明和注入,大大的减少了xml配置文件,同时也大大简化了项目的开发。
注解与xml共存:
应用的基本配置用xml,比如:数据源、资源文件等;
业务开发用注解,比如:Service中注入bean等;
@Contrller @Service 等 @Autowired
Spring3.x -Spring4.x
从Spring3.x开始提供了Java配置方式,使用Java配置方式可以更好的理解你配置的Bean,现在我们就处于这个时代,并且Spring4.x和Spring boot都推荐使用java配置的方式。
如@Configuration 和 @Bean的出现
Spring的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:
@Configuration 作用于类上,相当于一个xml配置文件;
@Bean 作用于方法上,相当于xml配置中的;
至此注解慢慢的取代了xml配置。
Spring5.x
Spring 5.0 GA版本于2017年9月28日发布。Spring 5.0开始支持JDK 8和Java EE 7,同时兼容JDK9。全面支持Servlet 3.1,还引入了一个全新的模块Spring WebFlux用于替代老话的 spring-webmvc;对Kotlin也有了更好的支持。
spring核心
环境搭建
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
Spring测试
方式1-new容器
public class IOCTest {
// 1 基于xml配置文件
@Test
public void test()throws Exception{
//通过xml初始化spring容器
ApplicationContext context = new
ClassPathXmlApplicationContext("beans.xml");
System.out.println(context.getBean(Date.class));
//向获取spring中所有的bean的类型
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
方式2-测试创建容器
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTestTest {
@Autowired
private ApplicationContext applicationContext;
@Test
public void test2() throws Exception{
System.out.println(applicationContext);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
Ioc-xml
Classpathxml*applictionContext
<?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
">
<bean id="myDate" class="java.util.Date">
scope="singleton" lazy-init="true" init-method="" destroy-method="" >
<property name="name" value="zs"></property>
<property name="otherBean" ref=""
</bean>
</beans>
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-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
">
<context:component-scan base-package="cn.itsource._03iocanno_">
</context:component-scan>
</beans>
配置注解
package cn.itsource._03iocanno_;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
//controller service repository componet
@Component
public class MyBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Autowired
private OtherBean otherBean;
public OtherBean getOtherBean() {
return otherBean;
}
public void setOtherBean(OtherBean otherBean) {
this.otherBean = otherBean;
}
}
Spring javaconfig-IOC
组件注册
1.创建项目并且导入pom
创建maven并导入一下内容:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
2.配置类&Bean注解&测试
@Configuration:加了这个注解的类就相当于传统的一个applicationContext-xxx.xml
@Bean:在标注了@Configuration的类里面的方式上面打上@bean就相当于在applicationContext-xxx.xml配置的一个
Dao的名字默认就是方法名,如果想改方法名使用@Bean(“beanName”)
package cn.itsource._04iocjavaconfig_;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //相当于原来的applicationContext-x.xml
public class IocConfig {
/**
* <bean id="myBean" class="cn.itsource._04iocjavaconfig_.MyBean"></bean>
* @return
*/
@Bean
public MyBean myBean(){
return new MyBean();
}
}
package cn.itsource._04iocjavaconfig_;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* javaconfig配置bean其实就是以配置类(@Configration)代替xml配置,通过@Bean的方式配置bean
* 获取容器
* new的方式: new AnnotationConfigApplicationContext(IocConfig.class);
* spring 测试的方式: @ContextConfiguration(classes = IocConfig.class)
*/
//方式2: springtest
@RunWith(SpringJUnit4ClassRunner.class)
//不用xml,直接指定配置类
@ContextConfiguration(classes = IocConfig.class)
public class SpringTestTest {
@Autowired
private ApplicationContext applicationContext;
//junit测试 AnnotationConfigApplicationContext注解方式,需要传入配置类
@Test
public void test1() throws Exception{
//spring测试-从容器中获取bean- 获取容器(ApplicatitonContext)
// 1 直接new 配置类就相当于原来spring配置文件
ApplicationContext context =
new AnnotationConfigApplicationContext(IocConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
@Test
public void test2() throws Exception{
System.out.println(applicationContext);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
3.@ComponentScan扫描bean
我们原来使用spring的使用不会在xml中一个一个配置bean,我们在再类上加上@Repository,@Service,@Controller @Component,并且注入时可以使用@AutoWired的注解注入。 这一切的功能都需要我们配置包扫描<context:component-scan base-package=“cn.itsource”/>.
然而现在注解驱动开发已经没有了配置文件,不能配置。但是提供了@ComponentScan,我们可以在配置类上面加上这个注解也是一样,并且也能扫描配置包项目的相关注解,也能完成自动注入。
a.基本语法
配置类:
//注解类==配置文件
@Configuration //告诉spring这是一个注解类
@ComponentScan("cn.itsource")
public class MainConfig {
//相当于在xml中配置了<bean id="" class="cn.itsource.dao.UserDao"><bean/>
@Bean("userDao") //指定bean的名字
public UserDao userDao01(){
return new UserDao();
}
}
Dao:不变还使用Bean方式
Service:
@Service
public class UserService {
public User getUser(Long id){
System.out.println("userservice...");
return null;
}
}
Controller:
@Controller
public class UserController {
//先不拷贝页面,直接打印即可
public User getUser(Long id){
System.out.println("usercontroller...");
return null;
}
}
测试:
ApplicationContext context = new AnnotationConfigApplicationContext
(MainConfig.class);
for (String beanName : context.getBeanDefinitionNames()) {
System.out.println(beanName);
}
b.高级语法
//注解类==配置文件
@Configuration //告诉spring这是一个注解类
//多个扫描配置方法1:配置多个ComponentScan
//@ComponentScan(value = "cn.itsource")
//@ComponentScan(value = "cn.itsource")
//includeFilters = Filter[] 包含过滤器
//excludeFilters = Filter[] 排除过滤器
//useDefaultFilters = 使用默认过滤器
//多个扫描配置方法2:使用ComponentScans
@ComponentScans(value = {
@ComponentScan(
value = "cn.itsource"
// ,excludeFilters = { //排除 //excludeFilters = Filter[] 排除过滤器
// @ComponentScan.Filter(type = FilterType.ANNOTATION
// ,classes = {Controller.class})
// }
,includeFilters = {//includeFilters = Filter[] 包含过滤器
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {
Controller.class
})
}
,useDefaultFilters = false //关闭默认全部扫描includeFilters才能生效
)
})
public class MainConfig {
//相当于在xml中配置了<bean id="" class="cn.itsource.dao.UserDao"><bean/>
@Bean("userDao") //指定bean的名字
public UserDao userDao01(){
return new UserDao();
}
}
注意1分开测试排除和包含
注意2:其他配置类影响-本身扫描也包含配置类
4.Bean详情-@Scope 组件范围&@Lazy 懒加载-认识
设置bean的名称
1)@Scope单例测试
2)@Lazy懒加载
5.Bean详情-注入
1 new 不在容器中
2 在容器中,调用方法 ok
3 @AutoWare,注入再设置
4 构造函数注入-推荐
public MyBean xxx(){
// 方式1:创建对象直接设置值,没有在spring中,不较注入
// OtherBean otherBean = new OtherBean();
// MyBean myBean = new MyBean();
// myBean.setOtherBean(otherBean);
// 方式2:直接调用方法
// MyBean myBean = new MyBean();
// // 智能发现如果已经通过该方法注册了bean,直接注入就ok,不会再新创建一个了。
// myBean.setOtherBean(otherBean());
//方式3:对注入的bean进行设置值
MyBean myBean = new MyBean();
myBean.setOtherBean(otherBean);
return myBean;
}
//方式4 通过构造函数进行注入 推荐使用
@Bean
public MyBean yyy(OtherBean otherBean){
return new MyBean(otherBean);
}
@Bean
public OtherBean otherBean(){
return new OtherBean();
}
6.@Conditional-按照条件注册
@Conditional(value = LinuxCondition.class) //放到类上面下面所有方法都生效,但是如果方法上加了优先级更高
public class MainConfig1 {
//相当于在xml中配置了<bean id="" class="cn.itsource.dao.UserDao"><bean/>
@Bean("userDao") //指定bean的名字
//@Scope(value = "protoType") //默认值为为单实例,默认值为是创建容器时就创建对象
@Lazy //只对单实例有用,表示创建容器时不创建对象,只有第一次使用时创建对象
public UserDao userDao01(){
return new UserDao();
}
@Bean
public UserDao userDaoLinux(){
return new UserDao();
}
//可以加到方法上面,也可以加到类上面. 根据当前os.name的环境来判断
@Bean
@Conditional(value = WindowsCondition.class)
public UserDao userDaoWindows(){
return new UserDao();
}
}
/**
* @author yaohuaipeng
* @date 2019/7/15-12:11
*/
public class WindowsCondition
implements Condition {
/**
*
* @param context conditionContext条件上下文,可以获取一些信息,来判断是否条件
* @param annotatedTypeMetadata 当前方法或注解类的注解类型元数据信息
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
//常用方法
//1 获取beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2 获取类家长群
ClassLoader classLoader = context.getClassLoader();
//3 获取当前运行环境
Environment environment = context.getEnvironment();
//4 获取bean的注册器,获取手动注册bean到spring容器
BeanDefinitionRegistry registry = context.getRegistry();
String osName = environment.getProperty("os.name");
if (osName.contains("Windows")){
return true;
}
return false;
}
}
测试:
/**
* 按照条件进行注册
*/
@Test
public void testCondition ()
{
ApplicationContext context = new AnnotationConfigApplicationContext
(MainConfig.class);
System.out.println(context.getEnvironment().getProperty("os.name"));
String[] beanNames = context.getBeanNamesForType(UserDao.class);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
7.@Import
//注解类==配置文件
@Configuration //告诉spring这是一个注解类
@Import({RedColor.class, GreenColor.class, MyImportSelector.class, My r.class})
public class MainConfig {
}
/**
* 创建bean的方式
* 方式1:@ComponentScan+注解(@Controller+@Service+@Repository+@Compont)-自己创建的bean
* 方式2:@Bean 别人的bean
* 方式3:@Import(快速向容器中注册一个bean)
* 1)@Import(要导入的组件),名称就是累的全限定名
* 2)ImportSelector:导入选择器,返回需要导入组件类的全限定名数组-springboot底层用的多
* 3)ImportBeanDefinitionRegistrar:通过bean定义注册器手动项目spring中容器中注册
* 方式4:FactoryBean的方式,返回的是getObject的类实例-和其他框架集成是用的多
*/
@Test
public void testImport ()
{
ApplicationContext context = new AnnotationConfigApplicationContext
(MainConfig.class);
String[] beanNames = context.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* @author yaohuaipeng
* @date 2019/7/15-14:18
*/
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//所打注解类上面所有的信息都能获取到
return new String[]{"cn.itsource.importtest.BlueColor",
"cn.itsource.importtest.YellowColor"};
}
}
package cn.itsource.importtest;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* @author yaohuaipeng
* @date 2019/7/15-14:23
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata 注解上下文
* @param beanDefinitionRegistry 注册器
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,
BeanDefinitionRegistry beanDefinitionRegistry) {
/**
* XxxColor:beanName
* bean的定义:
* RootBeanDefinition 表示没有层级关系之间注册到根上面
*/
beanDefinitionRegistry.registerBeanDefinition("XxxColor",
new RootBeanDefinition(XxxColor.class));
}
}
8.使用FactoryBean注册组件
//注解类==配置文件
@Configuration //告诉spring这是一个注解类
@Import({RedColor.class, GreenColor.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
@Bean
public PersonFactoryBean personFactoryBean(){
return new PersonFactoryBean();
}
}
/**
* @author yaohuaipeng
* @date 2019/7/15-14:30
*/
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Test
public void testFactoryBean ()
{
ApplicationContext context = new AnnotationConfigApplicationContext
(MainConfig.class);
//cn.itsource.factorybean.Person@69b794e2 不是返回factoryBean,而是里面的内容
Object person = context.getBean("personFactoryBean");
System.out.println(person);
Object person1 = context.getBean("&personFactoryBean");
System.out.println(person1.getClass());
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
组件生命周期
Bean生命周期:创建----初始化----销毁
我们可以自定义bean的初始化和销毁方法,并进行指定,bean在容器进行到对应生命周期时就会调用对应的方案. xml配置方式
1.创建
单实例bean:在容器创建是就进行指定
多实例bean:在每次使用时创建
2.初始化
容器创建完成,并赋值好,完成初始化
3.销毁
单实例bean:容器关闭时进行销毁
多实例bean:没有受spring管理,具体什么时候销毁有用户决定。
Spring Boot
它的出现解决了传统spring项目以下的问题:
1.配置负责繁多
每一个组件集成spring都需要编写对应配置文件,比如appplicationContext-xxx.xml
2.混乱的依赖管理
在spirng中想集成对应组件时,需要导入N多的pom,并且还有考虑版本。
我们使用SpringBoot创建java应用,只需填写很少配置和依赖就能快速搭建,并使用java –jar 启动它,就能得到一个生产级别的web工程。非常方便
Spring Boot特点
Spring Boot 主要目标是:
- 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
- 开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数(.properties),即可快速摆脱这种方式。
- 提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等
- 绝对没有代码生成,也无需 XML 配置。
Spring boot入门
1.搭建项目
a.创建springboot_01_helllo 项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
b.码测试
1)新建启动类(App – Main方法)
2)新建一个Controller类
3)测试代码
运行:App
浏览器:http://localhost:8080/hello