Spring注解
环境说明:spring 4.3.13.RELEASE,jdk1.8
一、容器
1、组件注册
1、@Configuration @Bean 组件注册
@Configuration标识的类为配置类,其实是一个@Component组件
@Bean 把bean注册到spring的容器中去
基于配置类
@Configuration//告诉spring这是一个配置类
public class BeanConfig {
//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person001(){
return new Person("marry", 20);
}
}
基于传统xml方式
<?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.hobart.spring.bean.Person">
<property name="age" value="18"></property>
<property name="name" value="tom"></property>
</bean>
</beans>
2、@ComponentScan 组件扫描
扫描某个包下的组件到容器中去
value:指定要扫描的包
excludeFilters = Filter[] :指定扫描的时候按照什么规则排除哪些组件
includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件(useDefaultFilters=false)关闭默认扫描方式
@Configuration//告诉spring这是一个配置类
@ComponentScan(value="com.hobart.spring",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})
})
//@ComponentScans({
// @ComponentScan(value="com.hobart.spring",includeFilters={
// @Filter(type=FilterType.ANNOTATION,classes={Controller.class})
// },useDefaultFilters=false)
//})
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除哪些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件(useDefaultFilters=false)关闭默认扫描方式
public class BeanConfig {
}
xml方式
<?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-4.3.xsd">
<!-- 包扫描、只要标注了
@Controller、@Service、@Repository、@Component 都会被注册到容器中去 -->
<!-- use-default-filters=false 关闭默认的扫描方式 -->
<context:component-scan base-package="com.hobart.spring" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
排除组件和包含组件中@Filter的分类:
FilterType.ANNOTATION :按照注解
FilterType.ASSIGNABLE_TYPE :按照给定的类型
FilterType.ASPECTJ :使用Aspectj表达式
FilterType.REGEX :按照正则表达式
FilterType.CUSTOM :自定义Filter
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import com.hobart.spring.bean.Person;
import com.hobart.spring.service.BookService;
/**
* 配置类==配置文件beans.xml
* @author hobart
*
*/
@Configuration//告诉spring这是一个配置类
//@ComponentScan(value="com.hobart.spring",excludeFilters={
// @Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})
//})
@ComponentScans({
@ComponentScan(value="com.hobart.spring",includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class})
},useDefaultFilters=false)
})
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除哪些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件(useDefaultFilters=false)关闭默认扫描方式
//FilterType.ANNOTATION :按照注解
//FilterType.ASSIGNABLE_TYPE :按照给定的类型
//FilterType.ASPECTJ :使用Aspectj表达式
//FilterType.REGEX :按照正则表达式
//FilterType.CUSTOM :自定义Filter
public class BeanConfig {
//给容器中注册一个Bean,类型为返回值的类型,id默认是用方法名作为id
@Bean("person")
public Person person001(){
return new Person("marry", 20);
}
}
自定义FilterType.CUSTOM 要实现org.springframework.core.type.filter.TypeFilter接口
package com.hobart.spring.filter;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:读取到的当前正在扫描类的信息
* metadataReaderFactory:可以获取其他任何类的信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
annotationMetadata.getAnnotationTypes().forEach(System.out::println);
//获取当前正在扫描类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println(">>>>>>"+className);
//包含er的组件注册到容器当中
if(className.contains("er")){
return true;
}
return false;
}
}
3、@Scope 设置组件的作用域
prototype :多实例的,ioc容器启动不会调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象
singleton :单实例的(默认值):ioc容器启动会调用方法创建对象到ioc容器中。以后每次获取都是从容器(map.get())中拿
request :同一次请求创建一个实例 (web环境下)
session :同一个session创建一个实例 (web环境下)
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.hobart.spring.bean.Person;
@Configuration
public class ScopeBeanConfig {
/**
* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
* @return
*
* prototype :多实例的,ioc容器启动不会调用方法创建对象放在容器中,每次获取的时候才会调用方法创建对象
*
* singleton :单实例的(默认值):ioc容器启动会调用方法创建对象到ioc容器中。以后每次获取都是从容器(map.get())中拿
*
* request :同一次请求创建一个实例 (web环境下)
*
* session :同一个session创建一个实例 (web环境下)
*
*/
@Scope("prototype")
@Bean
public Person person(){
System.out.println("创建Person...");
return new Person("tom", 28);
}
}
xml配置方式
<?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.hobart.spring.bean.Person" scope="prototype">
<property name="age" value="18"></property>
<property name="name" value="tom"></property>
</bean>
</beans>
4、@Lazy 懒加载
这个注解主要是针对单实例Bean:默认在容器启动时创建对象
懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.hobart.spring.bean.Person;
@Configuration
public class ScopeBeanConfig {
@Lazy
@Bean
public Person person(){
System.out.println("创建Person...");
return new Person("tom", 28);
}
}
5、@Conditionnal 按条件注册组件
修饰方法:对某个方法满足条件,注册组件
修饰类:对类下所有方法,满足条件才会注册组件
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.hobart.spring.bean.Person;
import com.hobart.spring.condition.LinuxCondition;
import com.hobart.spring.condition.WindowsCondition;
/**
* 按条件注册组件
* @author hobart
*
*/
//加在类上满足这个条件,每个方法才能注册组件
@Conditional({WindowsCondition.class})
@Configuration
public class ConditionBeanConfig {
/**
* @Conditional:按一定的条件进行判断,满足条件给容器中注册bean
* @return
*/
@Bean
public Person person(){
return new Person("张三",28);
}
//如果是windows环境注册bean
@Conditional({WindowsCondition.class})
@Bean("bill")
public Person person1(){
return new Person("Bill Gates", 62);
}
//如果是linux环境注册bean
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person2(){
return new Person("Linus", 48);
}
}
package com.hobart.spring.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* 按linux系统条件注册bean
* @author hobart
*
*/
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO 是否时linux系统
//1.能获取到ioc容器使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3.获取当前环境的信息
Environment environment = context.getEnvironment();
//4.获取Bean定义注册类
BeanDefinitionRegistry registry = context.getRegistry();
//是否包含某个bean
boolean containsBeanDefinition = registry.containsBeanDefinition("person");
String property = environment.getProperty("os.name");
if(property.contains("linux")){
return true;
}
return false;
}
}
6、@Import 快速导入组件
1、@Import 快速给容器中导入一个组件
1)、@Import(要导入到容器的组件):容器中就会注册这个组件,id默认为全类名
2)、ImportSelector:返回需要导入的组件的全类名数组;
3)、ImportBeanDefinitionRegistrar:手动注册Bean
直接类名的class导入
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.hobart.spring.bean.Color;
import com.hobart.spring.bean.Person;
import com.hobart.spring.bean.Red;
/**
* @Import 快速导入一个组件
* @author hobart
*
*/
@Configuration
@Import(value={Color.class,Red.class})//导入组件 id为全类名
public class ImportBeanConfig {
@Bean
public Person person(){
return new Person("Import", 28);
}
}
ImportSelector导入选择器
package com.hobart.spring.condition;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* 类名选择器
* @author hobart
*
*/
public class MyImportSelector implements ImportSelector {
/**
* 返回值就是导入到容器的组件全类名
* AnnotationMetadata:当前标注@Import注解类的所有注解信息
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//自定义逻辑返回
//注意:这地方不要返回空,否则会空指针
return new String[]{"com.hobart.spring.bean.Blue","com.hobart.spring.bean.Blank"};
}
}
@Configuration
@Import(value={Color.class,Red.class,MyImportSelector.class})//自定义类选择器,如上
public class ImportBeanConfig {
@Bean
public Person person(){
return new Person("Import", 28);
}
}
ImportBeanDefinitionRegistrar手动注册Bean
package com.hobart.spring.condition;
import org.springframework.beans.factory.config.BeanDefinition;
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;
import com.hobart.spring.bean.RainBow;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar{
/**
* AnnotationMetadata:当前标注@Import注解类的所有注解信息
* BeanDefinitionRegistry:BeanDefinition的注册类;
* 把所有需要添加到容器中的bean 调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//根据Bean的id判断容器是否存在某个bean
boolean hb1 = registry.containsBeanDefinition("com.hobart.spring.bean.Red");
boolean hb2 = registry.containsBeanDefinition("com.hobart.spring.bean.Blue");
if(hb1 && hb2){//如果存在哪么就注册
//指定Bean的Id
//指定Bean的定义信息(Bean的类型,Bean的作用域等等)
BeanDefinition beanDefinition=new RootBeanDefinition(RainBow.class);
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
@Configuration
@Import(value={Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})//自定义类bean的注册
public class ImportBeanConfig {
@Bean
public Person person(){
return new Person("Import", 28);
}
}
7、FactoryBean 工厂方式注册组件
1、默认获取到的是工厂Bean调用getObject创建的对象
2、要获取工厂Bean本身,我们需要给id前面加一个&
package com.hobart.spring.condition;
import org.springframework.beans.factory.FactoryBean;
import com.hobart.spring.bean.Color;
public class ColorFactoryBean implements FactoryBean<Color> {
//获取Bean的实例
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...getObject");
return new Color();
}
//获取Bean的类型
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* true:单实例,在容器中只创建一个实例对象
* false:多实例,每次获取都创建一个实例对象
*/
@Override
public boolean isSingleton() {
return true;
}
}
/**
* 工厂方式注册组件
* @author hobart
*
*/
@Configuration
public class FactoryBeanConfig {
/**
* 工厂Bean获取的是调用getObject创建的对象
* @return
*/
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
public class IOCTest {
@Test
public void testFactoryBean(){
ApplicationContext context = new AnnotationConfigApplicationContext(FactoryBeanConfig.class);
System.out.println("IOC容器初始化完成......");
//实际上是获取的 Bean工厂getObject返回的对象
//而且是懒加载的方式
Object bean = context.getBean("colorFactoryBean");
Object bean2 = context.getBean("colorFactoryBean");
System.out.println(bean == bean2);
System.out.println("Bean的类型:"+bean.getClass());
//若要从容器中获取Bean工厂的组件 前面加个&
Object beanFactory = context.getBean("&colorFactoryBean");
System.out.println(beanFactory);
}
}
组件注册总结
组件注册几种方式总结:
1、包扫描+组件标注注解(@Controller,@Service,@Repository,@Component)主要应用自己写的类
2、@Bean 导入第三方包的组件
3、@Import 快速给容器中导入一个组件
1)、@Import(要导入到容器的组件):容器中就会注册这个组件,id默认为全类名
2)、ImportSelector:返回需要导入的组件的全类名数组;
3)、ImportBeanDefinitionRegistrar:手动注册Bean
4、FactoryBean 工厂方式注册组件
2、组件生命周期
bean的生命周期:
bean创建—初始化—销毁的过程
容器管理bean的生命周期:
我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
构造(对象创建)
单实例:在容器启动的时候创建对象
多实例:在每次获取的时候创建对象
BeanPostProcessor.postProcessBeforeInitialization 初始化方法之前调用
初始化:
对象创建完成,并赋值好,调用初始化方法。。。
BeanPostProcessor.postProcessAfterInitialization 初始化方法之后调用
销毁:
单实例:容器关闭的时候销毁
多实例:容器不会管理这个bean,容器不会调用销毁方法。
xml配置方式
<?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-4.3.xsd">
<bean id="person" class="com.hobart.spring.bean.Person" init-method="init" destroy-method="destroy">
<property name="age" value="18"></property>
<property name="name" value="tom"></property>
</bean>
</beans>
1、 @Bean注解指定初始化和销毁方法
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.hobart.spring.bean.Car;
/**
* bean的生命周期
* bean的创建---初始化---销毁过程
* @author hobart
*
*/
@Configuration
public class LifeCycleBeanConfig {
@Bean(initMethod="init",destroyMethod="destroy")
public Car car(){
return new Car();
}
}
//测试
@Test
public void testBeanMethod(){
//创建容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(LifeCycleBeanConfig.class);
//单实例Bean在容器创建时创建且初始化
System.out.println("ioc 容器启动完成....");
//多实例Bean获取时才创建且初始化
Car car = context.getBean(Car.class);
context.close();
}
2、实现接口 InitializingBean 和 DisposableBean
package com.hobart.spring.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* 属性赋值好后执行初始化方法
*
* @author hobart
*
*/
public class Cat implements InitializingBean, DisposableBean {
public Cat() {
System.out.println("cat...constructor...");
}
@Override
public void destroy() throws Exception {
System.out.println("cat...destroy...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("cat...afterPropertiesSet...");
}
}
3、JSR250注解@PostConstruct 和 @PreDestroy
@PostConstruct:在bean创建完成并且属性赋值完成,来执行初始化方法。
@PreDestroy:在容器销毁bean之前通知我们进行清理工作。
package com.hobart.spring.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* JSR250注解
* @author hobart
*
*/
public class Dog {
public Dog() {
System.out.println("dog...constructor...");
}
//对象创建完成和属性赋值完成调用
@PostConstruct
public void setUp(){
System.out.println("dog...@PostConstruct...");
}
//容器移除对象之前
@PreDestroy
public void cleanUp(){
System.out.println("dog...@PreDestroy...");
}
}
4、BeanPostProcessor Bean的后置处理器
在bean初始化前后进行一些处理工作:
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作
spring的底层对BeanPostProcessor 的使用
bean的赋值,注入其他组件,@Autowired ,生命周期注解功能,@Async 等等
package com.hobart.spring.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization.."+beanName+"=>"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization.."+beanName+"=>"+bean);
return bean;
}
}
3、属性赋值@Value注解
使用@Value注解标注属性:
1、注解中直接赋值
2、spEL表达式:#{}
3、获取配置文件注入到容器的配置值:${}
public class Student {
//使用@Value注解标注属性
//1、注解中直接赋值
//2、spEL表达式:#{}
//3、获取配置文件注入到容器的配置值:${}
@Value("张三")
private String name;
@Value("#{30-2}")
private Integer age;
@Value("${student.nickName}")
private String nickName;
//省略get/set
}
/**
* 属性赋值
*
* @author hobart
*
*/
@Configuration
//导入配置文件到上下文
@PropertySources(value = { @PropertySource(
value = { "classpath:/student.properties" }) })
//@PropertySource(value={ "classpath:/student.properties"})
public class PropertyValuesBeanConfig {
@Bean
public Student student() {
return new Student();
}
}
//测试
public class IOCTest_PropertyValues {
@Test
public void testPropertyValue(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(PropertyValuesBeanConfig.class);
console(context);
Student student = (Student) context.getBean("student");
System.out.println("--==>"+student);
//导入的配置文件也从容器中获取
ConfigurableEnvironment environment = context.getEnvironment();
System.out.println(environment.getProperty("student.nickName"));
context.close();
}
}
xml方式导入配置文件
<?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-4.3.xsd">
<context:property-placeholder location="classpath:student.properties"/>
</beans>
4、自动装配
1、@Autowired自动注入
1)、默认按类型去容器中找对应的组件:applicationContext.getBean(UserDao.class);
2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找:
applicationContext.getBean(“userDao”);
3)、@Qualifier(“userDao”):使用@Qualifier注解指定需要装配组件的id,而不是属性名
4)、自动装配默认一定要将属性赋值好,如果容器中没有就会报错;
可以使用@Autowired(required=false)
5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
也可以继续使用@Qualifier指定需要装配的bean的名字
@Service
public class UserService {
@Qualifier("userDao")
@Autowired(required=false)
private UserDao userDao2;
public void showDao(){
System.out.println(userDao2.getLabe());
}
}
@Repository
public class UserDao {
private String labe="1";
public String getLabe() {
return labe;
}
public void setLabe(String labe) {
this.labe = labe;
}
}
/**
* 自动装配
*
* @author hobart
*
*/
@Configuration
@ComponentScan(basePackages = { "com.hobart.spring.controller",
"com.hobart.spring.service", "com.hobart.spring.dao" })
public class AutowiredBeanConfig {
@Primary
@Bean("userDao2")
public UserDao userDao(){
UserDao dao=new UserDao();
dao.setLabe("2");
return dao;
}
}
//测试
public class IOCTest_Autowired {
@Test
public void testAutowired(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredBeanConfig.class);
UserController userController = context.getBean(UserController.class);
userController.show();
UserService userService = context.getBean(UserService.class);
System.out.println(userService);
userService.showDao();
context.close();
}
}
2、Spring还支持使用@Resource(JSR250)和@Inject(JSR330) {java的规范注解}
@Resource:
可以和@Autowired一样实现自动装配功能;默认是按组件名称进行装配的;
没有能支持@Primary功能没有支持@Autowired(reqiured=false);
@Inject:
需要导入javax.inject的包,和@Autowired的功能一样,没有reqiured=false的功能;
@Autowired是Spring定义的;@Resource 和@Inject是java的规范
Spring源码就是AutowiredAnnotationBeanPostProcessor 这个Bean的后置处理器来实现自动装配功能的
3、@Autowired 构造、方法,参数注入
@Autowired注解可以修饰属性、构造器、方法、参数:都是从容器中获取参数组件的值
1)、{标在方法位置}:@Bean+方法参数;参数从容器中获取;默认不写@Autowired
效果一样,都能自动注入容器的组件
2)、{标在构造器上}:如果组件只有一个有参构造,这个有参够造的@Autowired可以省略,参数的位置组件还是可以从容器中获取
3)、{标在参数位置}:从容器获取组件
public class Boss {
private Car car;
//如果只有一个有参构造这个注解可以省略
@Autowired
public Boss(Car car) {
this.car=car;
}
public Car getCar() {
return car;
}
//@Autowired
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Boss [car=" + car + "]";
}
}
/**
* @Autowired 的方法 构造 参数注入
* @author hobart
*/
@Configuration
@Import(value={Car.class,Boss.class})
public class AutowiredBeanConfig2 {
//这个参数的@Autowired注解可以省略的
//方法的参数是从容器中获取组件
@Bean
public Color color(Car car){
Color color=new Color();
color.setCar(car);
return color;
}
}
//测试
public class IOCTest_Autowired {
@Test
public void testAutowired2(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredBeanConfig2.class);
Boss boss = context.getBean(Boss.class);
System.out.println(boss);
Car car = context.getBean(Car.class);
System.out.println(car);
Color color = context.getBean(Color.class);
System.out.println(color.getCar());
context.close();
}
}
4、注入Spring的组件
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,XXX);
自定义组件实现xxxAware接口;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
把Spring底层一些组件注入到自定义的Bean中;
/**
* 注入Spring的组件
* Aware的子接口
* 底层原理实现都是Bean后置处理器实现这些功能的
* @author hobart
*
*/
public class Bank implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的IOC容器:"+applicationContext);
this.applicationContext=applicationContext;
}
@Override
public void setBeanName(String name) {
System.out.println("当前Bean在容器中的名字:"+name);
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
//System.out.println("spEl#{}和获取上下文${}解析器");
System.out.println("环境参数:"+resolver.resolveStringValue("${os.name}"));
System.out.println("spEl表达式:"+resolver.resolveStringValue("#{20*10}"));
}
}
/**
* Aware子接口的实现类注入Spring底层组件
* @author hobart
*
*/
@Configuration
@Import(value={Bank.class})
public class AwareBeanConfig {
}
//测试
public class IOCTest_Autowired {
@Test
public void testAware(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareBeanConfig.class);
System.out.println("创建的IOC容器--=="+context);
context.close();
}
}
5、@Profile 根据环境注册组件
指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能生效
3)、没有标注环境标识的bean在任何环境下都是加载的。
/**
* @Profile 注解根据不同的环境参数来注册组件
*
* @author hobart
*
*/
//@Profile("test") //修饰类满足这个环境参数类中的组件才注册
@PropertySource(value={"classpath:/datasource.properties"})
@Configuration
public class ProfileBeanConfig implements EmbeddedValueResolverAware{
@Value("${jdbc.user}")
private String userName;
private String driverClass;
//@Profile("default") //这个是spring默认的环境参数
@Bean
public Blank blank(){
return new Blank();
}
@Profile("test")
@Bean("testDataSource")
public DataSource testDataSource(@Value("jdbc.pwd") String password){
DataSource dataSource=new DataSource();
//属性赋值
dataSource.setUserName(userName);
//方法参数
dataSource.setPassword(password);
//Aware子接口获取环境解析类
dataSource.setDriverClass(driverClass);
//测试环境
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource devDataSource(@Value("jdbc.pwd") String password){
DataSource dataSource=new DataSource();
dataSource.setUserName(userName);
dataSource.setPassword(password);
dataSource.setDriverClass(driverClass);
dataSource.setUrl("jdbc:mysql://localhost:3306/dev");
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource prodDataSource(@Value("jdbc.pwd") String password){
DataSource dataSource=new DataSource();
dataSource.setUserName(userName);
dataSource.setPassword(password);
dataSource.setDriverClass(driverClass);
dataSource.setUrl("jdbc:mysql://localhost:3306/prod");
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.driverClass=resolver.resolveStringValue("${jdbc.driverClass}");
}
}
//测试
public class IOCTest_Profile {
//编码设置
@Test
public void testProfile2(){
//创建容器类
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//设置需要激活的环境
context.getEnvironment().setActiveProfiles("dev");
//注册容器
context.register(ProfileBeanConfig.class);
//刷新容器
context.refresh();
String[] beanNames = context.getBeanNamesForType(DataSource.class);
for(String name:beanNames){
System.out.println(name);
}
System.out.println(context.getBean(Blank.class));
context.close();
}
//1.执行传入参数:-Dspring.profiles.active=test
@Test
public void testProfile1(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProfileBeanConfig.class);
String[] beanNames = context.getBeanNamesForType(DataSource.class);
for(String name:beanNames){
System.out.println(name);
}
System.out.println(context.getBean(Blank.class));
context.close();
}
}
5、AOP
aop:动态代理就是aop思想
指在程序运行期间动态的将某段代码切入到指定方法指定位置进行的编程方式
spring的aop基于注解方式使用分为以下几步:
1、导入aop模块;Spring AOP(spring-aspects)
2、定义一个业务逻辑类(MathCalculator);在业务逻辑运行的时候将日志进行打印(方法前,方法返回)
3、定义一个日志切面类(LogAspct):切面类里面的方法需要动态感知业务类方法运行到哪一步
通知方法:
前置通知(@Before):在目标方法(div)运行之前运行
后置通知(@After):在目标方法(div)运行结束之后运行
返回通知(@AfterReturning):在目标方法(div)正常返回之后运行
异常通知(@AfterThrowing):在目标方法(div)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoing.procced())
4、给切面类的目标方法标注何时何地运行
5、将切面类和业务逻辑类(目标方法所在的类)都加入到容器中
6、必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
7、给配置类加一个@EnableAspectJAutoProxy {开启基于注解的aop模式}
这个注解类似xml中
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
业务逻辑类
package com.hobart.spring.aop;
/**
* 数字计算器
*
* @author hobart
*
*/
public class MathCalculator {
public int div(int x, int y) {
System.out.println("--==MathCalculator...div...");
return x / y;
}
}
切面类
package com.hobart.spring.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 定义的日志切面
* @Aspect 注解告诉容器为一个切面
* @author hobart
*
*/
@Aspect
public class LogAspct {
//抽取公共的切入表达式
//要切入的位置 利用切面表达式
@Pointcut("execution(public int com.hobart.spring.aop.MathCalculator.*(..))")
public void pointCut(){}
@Before("pointCut()")
public void logBefore(JoinPoint joinpoint) {
System.out.println(joinpoint.getSignature().getName()
+"=>前置通知...@Before..."+"参数为:"
+Arrays.asList(joinpoint.getArgs()));
}
//外部类使用的这个切面表达式
@After("com.hobart.spring.aop.LogAspct.pointCut()")
public void logAfter(JoinPoint joinpoint) {
//类似于finally
System.out.println(joinpoint.getSignature().getName()
+"=>后置通知...@After...");
}
//JoinPoint一定要出现参数表的第一位
@AfterReturning(value="pointCut()",returning="result")
public void logAfterReturning(JoinPoint joinpoint,Object result) {
System.out.println(joinpoint.getSignature().getName()
+"=>返回通知...@AfterReturning..."+"结果为:"
+result);
}
@AfterThrowing(value="pointCut()",throwing="exception")
public void logAfterThrowing(JoinPoint joinpoint,Throwable exception) {
System.out.println(joinpoint.getSignature().getName()
+"=>异常通知...@AfterThrowing..."+"异常为:"
+exception);
}
//@Around("pointCut()")
public void logAround(JoinPoint joinpoint) {
System.out.println(joinpoint.getSignature().getName()
+"=>环绕通知...@Around...");
}
}
配置类
package com.hobart.spring.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.hobart.spring.aop.LogAspct;
import com.hobart.spring.aop.MathCalculator;
/**
* 基于注解aop
* @author hobart
*
*/
@EnableAspectJAutoProxy//启用注解切面表达
@Configuration
public class AopBeanConfig {
@Bean
public MathCalculator mathCalculator(){
return new MathCalculator();
}
@Bean
public LogAspct logAspct(){
return new LogAspct();
}
}
测试类
package com.hobart.spring.ioc;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.hobart.spring.aop.MathCalculator;
import com.hobart.spring.config.AopBeanConfig;
public class IOCTest_AOP {
@Test
public void testAop(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopBeanConfig.class);
MathCalculator mathCalculator = context.getBean(MathCalculator.class);
mathCalculator.div(6, 3);
context.close();
}
}
总结
spirng注解为后续springboot学习打基础