public class User {
private Long id;
private String userName;
private String note;
}
@Configuration //加上配置注解
public class AppConfig {
@Bean(name = "user") //指定bean
public User initUser() {
User user = new User();
user.setId(1L);
user.setUserName("用户名");
user.setNote("节点");
return user;
}
}
private static Logger log = Logger.getLogger(ToTest.class);
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
log.info(user.getId());
log.info(user.getUserName());
}
getBean 每次拿到的都是同一个对象,使用时要注意,直接改对象内容,其他地方也会改变
Spring Ioc 容器是一个管理的bean的容器
所有的IoC容器都需要实现BeanFactory,它是一个顶级容器接口
BeanFactory有根据类型,和根据名字获取bean的,判断是否包含,是否单例,是否原型
默认情况下都是单例的, isPrototype 是否原型,与是否单例相反。是否原型为true,说明不是单例,每次都会创建一个新的bean
BeanFactory不够强大,设计了更高级的接口ApplicationContext 是beanFactory的子接口
现实中大部分容器都是ApplicationContext的实现类
基于注解的IOC容器 AnnotationConfigApplicationContext (springBoot常用)
Java简单对象 Plain Ordinary Java Object POJO
plain
英 [pleɪn] 美 [plen]
adj. 平的;简单的;朴素的;清晰的
n. 平原;无格式;朴实无华的东西
adv. 清楚地;平易地
ordinary
英 ['ɔːdɪn(ə)rɪ; -d(ə)n-] 美 ['ɔrdnɛri]
adj. 普通的;平凡的;平常的
n. 普通;平常的人(或事)
复数 ordinaries
一个一个的配置bean会很麻烦,所以有了装配bean
就是扫描装配 注解:@Component @ComponentScan
@Componet 标明那个类被扫描进入Spring Ioc容器
@ComponetScan 标明采用何种的策略,扫描装配
component
英 [kəm'pəʊnənt] 美 [kəm'ponənt]
adj. 组成的,构成的
n. 成分;组件;[电子] 元件
@Component("student")
public class Student {
@Value("1")
private Long id;
@Value("用户名")
private String userName;
@Value("note")
private String note;
}
@Configuration
@ComponentScan
public class AppConfig {
}
使用依然不变:
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
getBean
依然是单例的:可以BeanUtils.copyProperties(bean,bean2); 不改动元对象
basePackages 定义扫描的包
includeFilters excludeFilters 定义满足条件,和不满足条件 才去扫描,
条件用 @Filter去定义,里有一个type类型,classes定义注解类,pater定义正则式类
@ComponentScan("com.hua.huademo1.*")
@ComponentScan(basePackages = {"com.hua.huademo1.*"})
@ComponentScan(basePackageClasses = {Student.class})
@ComponentScan(basePackages = {"com.hua.huademo1.*"},excludeFilters = {@ComponentScan.Filter(classes = {User.class})})
org.apache.commons
commons-dbcp2
mysql
mysql-connector-java
在配置类加入
@Configuration
@ComponentScan(basePackages = "com.springboot.chapter3.*")
@Bean(name = "dataSource", destroyMethod = "close")
@Profile("dev")
public DataSource getDevDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/dev_spring_boot");
props.setProperty("username", "root");
props.setProperty("password", "123456");
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
@Configuration
@ComponentScan(basePackages = "com.hua.huademo2.*")
public class AppConfig {
}
@Component //定义为springBean
public class Dog implements Animal {
@Override
public void use() {
System.out.println("狗【" + Dog.class.getSimpleName()+"】是看门用的。");
}
}
@Component
public class BussinessPerson implements Person {
@Autowired //注入接口,实际注入的是实现类
private Animal animal = null;
@Override
public void service() {
this.animal.use();
}
@Override
public void setAnimal(Animal animal) {
this.animal = animal;
}
}
ApplicationContext ctx= new AnnotationConfigApplicationContext(AppConfig.class);
Person bean = ctx.getBean(BussinessPerson.class);
bean.service();
当一个接口有连个实现类时候,解决办法
@Autowired
private Animal cat = null; //注入的是 cat的实现类
使用注解,注解的权限高与上面的变量
@Component
@Primary 或者: @Qualifier("dog") //指定注入那个bean
public class Dog implements Animal {
在方法上注入
private Animal cat = null;
@Override
@Autowired
@Qualifier("dog") //指定注入那个bean
public void setAnimal(Animal animal) {
this.cat = animal;
}
@Autowired @Qualifier("dog") //还可以这样,直接写两个注解
public void setAnimal(Animal animal) {
this.cat = animal;
}
或者: 但是不能把 Autowired写在方法上(没用)
@Override
@Autowired
public void setAnimal(@Qualifier("dog") Animal animal) {
this.cat = animal;
}
但可以写在构造上:
public BussinessPerson(@Autowired @Qualifier("dog") Animal cat) {
this.cat = cat;
}
并不一定非要存在,可能为null
@Autowired(required = false)
往细了说就是:资源定位,Bean定义,发布Bean,实例化,依赖注入
默认发布bean定义之后,就开始创建对象,(调用构造)
可以用懒加载 在使用的时候,才调用对象
@Configuration
@ComponentScan(basePackages = "com.hua.huademo2.*",lazyInit = true)
public class AppConfig {
}
implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean
//后置初始化bean对所有的bean生效
@Component
public class BeanPostProcessorExample implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//6,postProcessBeforeInitialization
System.out.println("BeanPostProcessor调用" + "postProcessBeforeInitialization方法,参数【"
+ bean.getClass().getSimpleName() + "】【" + beanName + "】 ");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//9,postProcessAfterInitialization
System.out.println("BeanPostProcessor调用" + "postProcessAfterInitialization方法,参数【"
+ bean.getClass().getSimpleName() + "】【" + beanName + "】 ");
return bean;
}
}
@Component
public class BussinessPerson
implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private Animal animal = null;
@Override
public void service() {
this.animal.use();
}
@Override
@Autowired
@Qualifier("dog")
public void setAnimal(Animal animal) {
System.out.println("延迟依赖注入");
this.animal = animal;
}
@Override
public void setBeanName(String beanName) {
//1初始化
//2依赖注入
//这里是3,setBeanName
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanNameAware的setBeanName");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
//4,setBeanFactory
System.out.println("【" + this.getClass().getSimpleName() + "】调用BeanFactoryAware的setBeanFactory");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//5,setApplication
System.out.println("【" + this.getClass().getSimpleName() + "】调用ApplicationContextAware的setApplicationContext");
}
//6,在BeanPostProcessor中 postProcessBeforeInitialization
@PostConstruct
public void init() {
//7,自定义初始化 PostConstruct
System.out.println("【" + this.getClass().getSimpleName() + "】注解@PostConstruct定义的自定义初始化方法");
}
@Override
public void afterPropertiesSet() throws Exception {
//8,afterPropertiesSet
System.out.println("【" + this.getClass().getSimpleName() + "】调用InitializingBean的afterPropertiesSet方法");
}
//9,在BeanPostProcessor中 postProcessAfterInitialization
//10,生存期
@PreDestroy
public void destroy1() {
//11,自定义销毁方法 PreDestroy
System.out.println("【" + this.getClass().getSimpleName() + "】注解@PreDestroy定义的自定义销毁方法");
}
@Override
public void destroy() throws Exception {
//12,销毁的方法
System.out.println("【" + this.getClass().getSimpleName() + "】 DisposableBean方法");
}
}
1,初始化
延迟依赖注入 2,依赖注入
【BussinessPerson 3】调用BeanNameAware的setBeanName
【BussinessPerson 4】调用BeanFactoryAware的setBeanFactory
【BussinessPerson 5】调用ApplicationContextAware的setApplicationContext
【BeanPostProcessor 6】调用postProcessBeforeInitialization方法,参数【BussinessPerson】【bussinessPerson】
【BussinessPerson 7】注解@PostConstruct定义的自定义初始化方法
【BussinessPerson 8】调用InitializingBean的afterPropertiesSet方法
【BeanPostProcessor 9】调用postProcessAfterInitialization方法,参数【BussinessPerson】【bussinessPerson】
狗【Dog】是看门用的。 10,生存期
【BussinessPerson 11】注解@PreDestroy定义的自定义销毁方法
【BussinessPerson 12】 DisposableBean方法
最常用的:
@PostConstruct
@PreDestroy
使用bean指定方法:
@Bean(name = "dataSource", destroyMethod = "close") //,initMethod =
@Profile("test")
public DataSource getTestDataSource() {
@Configuration
@ComponentScan(basePackages = "com.example.*", //是要扫描的上层目录 User在com.example.demobenaware下
excludeFilters = {@ComponentScan.Filter(classes={UserService.class})})
public class AppConfig {
}
如果要扫User可以:@ComponentScan(basePackages = “com.example.demobenaware”)
@Data
@Component
@PropertySource("classpath:application.properties")
public class DataBaseProperties {
@Value("${book}")
private String url = null;
}
//可以不用引入
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
processor
英 ['prəʊsesə] 美 ['prɑsɛsɚ]
n. [计] 处理器;处理程序;加工者
database.driver-name=com.mysql.jdbc.Driver
database.password=123456
database.username=root
database.url=jdbc:mysql://localhost:3306/chapter3
@Component
public class DataBaseProperties {
@Value("${database.driver-name}") //配置这样database.driverName=com.mysql.jdbc.Driver 也是可以的,相同最好
private String driverName = null;
@Value("${database.url}")
private String url = null;
也可以放在set方法上
@Value("${database.username}")
public void setUsername(String username) {
this.username = username;
}
@Component
@ConfigurationProperties( "database")
public class DataBaseProperties {
private String driverName = null; //这里等于driver-name , @Value("${database.driver-name}") ,反过来不行
private String url = null;
}
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/chapter3
@Data
@Component
@ConfigurationProperties("spring.datasource")
public class DataBaseProperties {
private String driverClassName;
private String url;
private String username;
private String password;
public void setUsername(String username) {
System.out.println(username);
this.username = username;
}
public void setPassword(String password) {
System.out.println(password);
this.password = password;
}
}
默认只加载application.properties
想要加载其他的配置,
在@SpringBootApplication (里面也有扫描包)
或者:扫描包下
@ComponentScan(basePackages = "com.hua.huademo2.*") //,lazyInit = true
@PropertySource(value={"classpath:jdbc.properties"}, ignoreResourceNotFound=true)
@Data
@Component
@ConfigurationProperties("spring.datasource")//加在下面这两个文件里,这个开头的
@PropertySource(value = {"classpath:jdbc.properties","classpath:application.properties"})
public class DataBaseProperties {
private String book;
public void setBook(String book) {
System.out.println(book);
this.book = book;
}
}
spring.datasource.book=dddd
@SpringBootApplication(scanBasePackages = "com.*")
@PropertySource(value={"classpath:jdbc.properties"}, ignoreResourceNotFound=true)
@ImportResource(value = {"classpath:spring-other.xml"})
@Bean(name = "dataSource", destroyMethod = "close")
@Conditional(DatabaseConditional.class) //满足这个条件,才装配bean
public DataSource getDataSource(
@Value("${database.driverName}") String driver, //@Value 也可以在参数上写
@Value("${database.url}") String url,
@Value("${database.username}") String username,
@Value("${database.password}") String password
) {
Properties props = new Properties();
props.setProperty("driver", driver);
props.setProperty("url", url);
props.setProperty("username", username);
props.setProperty("password", password);
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
public class DatabaseConditional implements Condition {
/*
* @param context 条件上下文
* @param matadata 注释类型的元数据
* return true 装配bean 否则不装配
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return env.containsProperty("database.driverName") && env.containsProperty("database.url")
&& env.containsProperty("database.username") && env.containsProperty("database.password");
}
}
最顶级的接口BeanFactory的时候,有 isSingleton和 isPrototype 两个方法
一般容器:有单例 singleton和原型 prototype
javaEE容器,存在 page ,请求 request ,会话 session 和 应用 application
page是 jsp当前页面的作用域
作用域类型 | 使用范围 | 描述 |
---|---|---|
single | spring应用 | 单例 |
prototype | spring应用 | 原型,每次都会创建一个bean |
session | web应用 | HTTP会话 |
application | web应用 | web工程的生命周期 |
request | web应用 | 单次请求 |
globalSession | web应用 | 一个全局的http Session中,一个Bean定义对应一个实例,实践中基本不使用 |
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //默认是单例的
public class ScopeBean {
}
@Configuration
@ComponentScan
public class AppConfig {
}
AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);
ScopeBean bean = ctx.getBean(ScopeBean.class);
ScopeBean bean2 = ctx.getBean(ScopeBean.class);
System.out.println(bean==bean2);//默认是true
/@Scope(WebApplicationContext.SCOPE_REQUEST)/ 我也不会用
logging.level.root=DEBUG
logging.level.org.springframework=DEBUG
@Configuration
@ComponentScan(basePackages = "com.example.demo1.*")
public class AppConfig {
@Bean(name = "dataSource", destroyMethod = "close")
@Profile("dev")
public DataSource getDevDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/dev_spring_boot");
props.setProperty("username", "root");
props.setProperty("password", "15517");
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
@Bean(name = "dataSource", destroyMethod = "close")
@Profile("test")
public DataSource getTestDataSource() {
return dataSource;
}
}
#spring.profiles.active=test
spring.profiles.default=dev
java启动项目中配置 未测试
JAVA_OPTS="-Dspring.profiles.active=dev"
或者: idea vm options 配置 -Dspring.profiles.active=dev
idea参数
Active Profiles : test
java -Dspring.profiles.active=dev -jar demo1-0.0.1-SNAPSHOT.jar
public class Squirrel implements Animal {
@Override
public void use() {
System.out.println("松鼠可以采集松果");
}
}
@Configuration
@ComponentScan
@ImportResource(value = {"classpath:spring-other.xml"}) //springboot 在 resource 下 和
application.properties同目录
<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">
<bean id="squirrel" class="com.hua.demo3.Squirrel"/>
beans>
@Data
@ToString
@Component
@ConfigurationProperties( "database")
public class DataBaseProperties {
private String driverName = null;
private String url = null;
@Value("${database.driverName}") //为了适应这个,上面请加入:@PropertySource("classpath:application.properties")
private String driverName2 = null;
@Value("#{T(System).currentTimeMillis()}") //T 代表引入类,System long.*包下。使用的是静态的方法。
private Long initTime=null;
@Value("#{12345}")
private Long initTime2=null; //直接赋值
@Value("#{9.3E3}") //科学计算赋值
private Long initTime2=null;
@Value("#{3.12}") //浮点小数赋值
private float f;
@Value("#{squirrel.name?.toUpperCase()}") //取Spring Ioc容器bean的名称,这个bean还能在读取配置文件
private String use; //?代表判断这个属性是否为空,如果不为空才去执行toUpperCase方法
@Value("#{1+2}")
private int run;
@Value("#{squirrel.pi == 3.14f}")
private boolean piFlag;
@Value("#{squirrel.name +'连接的字符串'}")
private String strApp;
@Value("#{squirrel.pi > 1000 ? '大于' : '小于'}")
private String resultDesc;
@Value("#{squirrel.name eq 'com.mysql.jdbc.Driver'}")
private String strFlag;
}
#{} 启用spring表达式 有运算的功能
T() 引入类
System是 java.lang.*的包,默认加载的包,不用全路径,currentTimeMillis是静态方法
@Data
@Component
public class Squirrel {
@Value("#{3.12}") //浮点小数赋值
private float pi;
@Value("为何要连接???")
private String name;
}