- @Configuration & @Bean
- @DependsOn
- @ComponentScan
- @Scope 组件作用域
- @Lazy 懒加载
- @Conditional
- @Import
- @PostConstruct & @PreDestroy
- @PropertySource & @Value
- @Autowired & @Qualifier & @Primary
- @Resource & @Inject
- @Profile
- @EnableAspectJAutoProxy & @Aspect
- @EnableTransactionManagement & @Transactional
- @EventListener
- @WebServlet
- @HandlesTypes
- @EnableWebMvc
- servlet3.0-异步请求
- springmvc-异步请求
spring注解驱动开发笔记
整篇参考 Spring 注解驱动开发
学习视频 : 尚硅谷 - Spring 注解驱动开发
@Configuration & @Bean
1. 编写Person类 -> Person
...
2. 编写beans.xml -> 将Person注入到容器
/**传统方式
<?xml version="1.0" encoding="UTF-8"?>
<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="person" class="com.cdinit.springannotation.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="zhangsan"></property>
</bean>
</beans>
3. 从容器中获取bean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person p = (Person) applicationContext.getBean("person");
System.out.println(p);
*/
1.写一个配置类(配置类就等同于配置文件)
2.注册bean
/**注解方式
@Configuration //告诉spring这是一个配置类
public class MainConfig {
@Bean(name = "person1") // 给容器中注册一个bean;类型为返回值的类型 id默认用方法名作为id
public Person person(){
return new Person("lisi",20);
}
}
3.测试
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person p = (Person) applicationContext.getBean("person1");
// Person p = applicationContext.getBean(Person.class);
System.out.println(p);
*/
@DependsOn
// 依赖于某个java bean的创建而创建
@DependsOn({"xxxx"})
@ComponentScan
基本用法
// 包扫描
/**传统方式
xmlns:context="http://www.springframework.org/schema/context"
<context:component-scan base-package="com.cdinit"></context:component-scan>
*/
/**注解方式
在配置类中添加
@ComponentScan(value = "com.cdinit")
*/
@Configuration //告诉spring这是一个配置类
// excludeFilters 排除哪些组件
// includeFilters 只包含哪些组件
@ComponentScan(value = "com.cdinit" ,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Service.class)
},
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = RestController.class)
},
useDefaultFilters = false
)
public class MainConfig {
@Bean(name = "person1") // 给容器中注册一个bean;类型为返回值的类型 id默认用方法名作为id
public Person person(){
return new Person("lisi",20);
}
}
// 测试excludeFilters和includeFilters是否生效
public class MainTest {
public static void main(String[] args) {
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person p = (Person) applicationContext.getBean("person");
// System.out.println(p);
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
for (String s : applicationContext.getBeanDefinitionNames()) {
System.out.println(s);
}
}
}
@ComponentScan中Filter类型
- ANNOTATION 注解类型
- ASSIGNABLE_TYPE 指定的类型
- ASPECTJ 按照Aspectj的表达式
- REGEX 按照正则表达式
- CUSTOM 自定义规则
// CUSTOM规则
/**
1.编写MyTypeFilter 并实现 TypeFilter 接口
2.match方法中 实现自定义规则
*/
参考 Spring注解(@Bean、@ComponentScan、自定义TypeFilter)
@Scope 组件作用域
@Bean(name = "person1") // 给容器中注册一个bean;类型为返回值的类型 id默认用方法名作为id
// prototype:多实例 (ioc容器启动时候不会创建对象,获取对象的时候创建)
// singleton:单实例 (ioc容器启动会创建对象)
// request
// session
@Scope("prototype")
public Person person(){
System.out.println("add .....");
return new Person("lisi",20);
}
}
@Lazy 懒加载
针对单实例的bean,默认在容器启动的时候创建,而懒加载,容器启动不创建对象,第一次获取bean的时候创建
@Conditional
按照一定的条件进行判断,满足条件给容器中注册bean。spring,spring boot底层很常用
// 可以放在类上 也可以放在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
参考 Spring注解驱动开发@Conditional按照条件注册bean
@Import
给容器中注册组件:
-
包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
-
@Bean[导入的第三方包里面的组件]
-
@Import[快速给容器中导入一个组件]
-
- @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
-
- ImportSelector:返回需要导入的组件的全类名数组;
-
- ImportBeanDefinitionRegistrar:手动注册bean到容器中
- 使用Spring提供的 FactoryBean(工厂Bean);
-
- 默认获取到的是工厂bean调用getObject创建的对象
-
-
要获取工厂Bean本身,我们需要给id前面加一个&
&colorFactoryBean
-
参考 SpringBoot给容器中注册组件的四种方法(简易版)
@PostConstruct & @PreDestroy
@PostConstruct:初始化Bean(对象创建完成并赋值好)的时候调用 == 传统方式 init-method
@PreDestroy:容器关闭的时候调用(单实例) == 传统方式destroy-method;
多实例容器不会管理bean,容器不会调用销毁
public class Person {
private String name;
private Integer age;
...
@PostConstruct
public void init(){
System.out.println("init...");
}
@PreDestroy
public void destroy(){
System.out.println("destroy...");
}
}
其他方法:
- 通过让Bean实现InitializingBean,DisposableBean
public class Person implements InitializingBean,DisposableBean {
...
}
- BeanPostProcessor: bean的后置处理器,在bean初始化前后进行一些处理工作 , 参考Spring中的后置处理器BeanPostProcessor讲解
@PropertySource & @Value
使用@PropertySource读取配置文件(最好放在@Configuration标注的类上进行统一管理)
使用@Value(“${}”)取出配置文件的值
@Autowired & @Qualifier & @Primary
@Autowired(required = false) // required=false 有则注入,没有就算了
@Qualifier("bookRepository") // 指定装配
private BookRepository bookRepository2;
/**
@Primary 让Spring进行自动装配的时候,默认选择需要装配的bean,也可以继续使用@Qualifier 指定需要装配的bean的名称
@Qualifier 的权重大于 @Primary,如果指定了@Qualifier 则 @Primary失效
*/
@Primary
@Bean(name = "person2")
public Person person2(){
System.out.println("add .....");
return new Person("wangwu",25);
}
参考自动装配-@Autowired&@Qualifier&@Primary
@Resource & @Inject
@Resource(name = "pserson1")
private Person person;
参考
@Profile
自动装配-@Profile根据环境注册bean
注册bean
// 设置3个bean
@Configuration
@ComponentScan(value = "com.cdinit")
public class MainConfig {
@Bean("defaultPerson")
@Profile("default")
public Person personDefault(){
Person p = new Person();
p.setName("defaultPerson");
p.setAge(00);
return p;
}
@Bean("testPerson")
@Profile("test")
public Person personTest(){
Person p = new Person();
p.setName("testPerson");
p.setAge(11);
return p;
}
@Bean("devPerson")
@Profile("dev")
public Person personDev(){
Person p = new Person();
p.setName("devPerson");
p.setAge(22);
return p;
}
@Bean("releasePerson")
@Profile("release")
public Person personRelease(){
Person p = new Person();
p.setName("releasePerson");
p.setAge(33);
return p;
}
}
激活环境
1.在servlet上下文中进行配置(web.xml)
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>dev</param-value>
</context-param>
2.作为SpringMVC中的DispatcherServlet的初始化参数
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev</param-value>
</init-param>
3.spring-junit使用@ActiveProfiles进行激活
4.作为JNDI条目
5.作为环境变量
6.作为JVM的系统属性
7.application.properties配置文件
配置文件中添加:spring.profiles.active=dev
参考
@EnableAspectJAutoProxy & @Aspect
参考
先要加入依赖
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
或
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
注意:所以bean必须由spring管理才能使用切面
@EnableTransactionManagement & @Transactional
@Transactional 表示当前方法是一个事物方法
@EnableTransactionManagement 开启基于注解的事务功能
spring需要把事务管理器加入到容器中
@Bean
public DataSource dataSource(){
...
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dataSource());
}
spring boot可以直接使用
参考:Spring boot学习笔记:SpringBoot之事务管理@Transactional
@EventListener
web相关
@WebServlet
@HandlesTypes
参考:使用Servlet3.0新特性进行web开发小demo
@EnableWebMvc
springmvc定制,xml方式
<mvc:annotation-driven/>
添加注解,然后extends WebMvcConfigurerAdapter
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Override configuration methods...
}
详细参考:
SpringBoot 项目 @EnableWebMvc 注解应用总结
servlet3.0-异步请求
asyncSupported = true
AsyncContext asyncContext = req.startAsync();
@WebServlet(value = "/async", asyncSupported = true)
public class HelloAsyncServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
System.out.println("主线程开始:" + Thread.currentThread() + "start..." + System.currentTimeMillis());
// 开始异步处理
asyncContext.start(() -> {
try {
System.out.println("子线程开始:" + Thread.currentThread() + "start..." + System.currentTimeMillis());
sayHello();
asyncContext.complete();
// 获取响应
ServletResponse response = asyncContext.getResponse();
response.getWriter().write("异步执行完成");
System.out.println("子线程结束:" + Thread.currentThread() + "end..." + System.currentTimeMillis());
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
});
System.out.println("主线程结束:" + Thread.currentThread() + "end..." + System.currentTimeMillis());
}
public void sayHello() throws InterruptedException {
System.out.println("sayHello运行:" + Thread.currentThread() + "processing..." + System.currentTimeMillis());
Thread.sleep(3000);
}
}
springmvc-异步请求
@Controller
public class AsyncController {
@RequestMapping("async01")
@ResponseBody
public Callable<String> async01() {
System.out.println("主线程开始..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
Callable<String> callable = new Callable<String>() {
public String call() throws Exception {
System.out.println("子线程开始..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("子线程结束..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
return "Callable<String> async01()";
}
};
System.out.println("主线程结束..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
return callable;
}
}
参考: