一、Spring整体框架
二、Spring IOC
1、核心思想
资源不由资源使用者直接管理,而是由第三方管理,使用时通过第三方获取,这个第三方就是ioc容器。
代码意思就是,使用时通过自动装配的方式从ioc容器中获取,而不是直接new出相应对象
public class UserService{
@AutoWired
private UserDao userDao;
//而不是new出来
}
好处:
1、资源集中管理,实现资源的可配置和易管理。
2、降低耦合度,降低了使用资源双方的依赖程度。
2、bean的生命周期
2.1、生命周期分类
bean的创建—–>初始化—–>销毁
2.2、设置bean的初始化和销毁方法
A、通过@bean注解,指定init-method和destory-method参数。具体方法写在bean类中,代码如下
@Configuration
public class MainConfig { /
/指定了bean的生命周期的初始化方法和销毁方法.
@Bean(initMethod = "init",destroyMethod ="destroy")
public Car car() {
return new Car();
}
}
public class car {
public car(){
System.out.println("car的构造方法");
}
public void init(){
System.out.println("car的初始化方法");
}
public void destroy(){
System.out.println("car的销毁方法");
}
}
B、通过让bean实现InitializingBean和DisposableBean接口重写初始化和销毁方法,在类上用@Component等注解,注册到ioc容器中。代码如下
@Component
public class Person implements InitializingBean,DisposableBean {
public Person() {
System.out.println("Person的构造方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("person的初始化方法");
}
@Override
public void destroy() throws Exception {
System.out.println("person的销毁方法");
}
}
C、通过Spring的BeanPostProcessor的 bean的后置处理器来拦截所有bean创建过程
@Component
public class TulingBeanPostProcessor implements BeanPostProcessor {
//在init方法之前调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("TulingBeanPostProcessor...postProcessBeforeInitialization:"+beanName);
return bean;
}
//在init方法之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("TulingBeanPostProcessor...postProcessAfterInitialization:"+beanName);
return bean;
}
}
注意:BeanPostProcessor在bean的初始化前后工作,主要用于修改bean的属性
2.3、调初始化和销毁方法的时机
单实例模式:容器启动时,先创建对象,然后赋值,之后调初始化方法。容器关闭时调销毁方法
多实例模式:对象的创建、初始化、销毁都不受容器控制。而是在获取bean的时候创建对象、调初始化方法;不用时调销毁方法
3、常用注解
3.1、往ioc容器中添加组件的注解
A、@CompentScan +@Controller @Service @Respository @compent。适用于针对我们自己写的组件。代码如下
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"})
public class MainConfig {}
@Component
public class Person {}
注意:单纯的@Controller @Service @Respository @compent并不会往ioc容器中加组件,必须配合包扫描@CompentScan
扩展:包扫描注解@CompentScan的详细用法,代码如下
a、排除用法:排除@Controller注解修饰的和TulingService类的
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TulingService.class})
})
public class MainConfig {}
b、指定用法:指定只注入@Controller @Service注解修饰的
@Configuration
@ComponentScan(basePackages = {"com.tuling.testcompentscan"},includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class})
},useDefaultFilters = false)
public class MainConfig {}
注意,若使用指定用法,需要把useDefaultFilters属性设置为false(true表示扫描全部的)
B、@Bean。适用于导入第三方组件的类。代码如下
@Configuration
public class MainConfig {
@Bean
public Person person(){
return new Person();
}
}
扩展:
a、配置bean的作用域:@Scope。
//在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建好了)
@Bean
public Person person() {
return new Person();
}
//指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)
@Bean
@Scope(value = "prototype")
public Person person() {
return new Person();
}
// singleton 单实例的(默认)
// prototype 多实例的
// request 同一次请求
// session 同一个会话级别
b、bean的懒加载:@Lazy(主要针对单实例的bean。 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象)
@Bean
@Lazy
public Person person() {
return new Person();
}
c、符合条件才创建bean:@Conditional
场景:有二个组件TulingAspect 和TulingLog ,TulingLog组件是依赖于TulingAspect的组件,代码如下
//先定义判断条件
public class TulingCondition implements Condition {
/**
* @param context
* @param metadata
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//判断容器中是否有tulingAspect的组件
if(context.getBeanFactory().containsBean("tulingAspect")) {
return true;
}
return false;
}
}
@Configuration
public class MainConfig {
@Bean public TulingAspect tulingAspect() {
return new TulingAspect();
}
//如果容器中有tulingAspect的组件,那么tulingLog才会被实例化.
@Bean
@Conditional(value = TulingCondition.class)
public TulingLog tulingLog() {
return new TulingLog();
}
}
C、@Import。适用于导入第三方组件的类。代码如下
@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig { }
扩展:
a、通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)
public class TulingImportSelector implements ImportSelector {
//可以获取导入类的注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.tuling.testimport.compent.Dog"};
}
}
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class})
public class MainConfig { }
b、通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)
public class TulingBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//创建一个bean定义对象
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
//把bean定义对象导入到容器中
registry.registerBeanDefinition("cat",rootBeanDefinition);
}
}
@Configuration
@Import(value = {Person.class, Car.class, TulingImportSelector.class, TulingBeanDefinitionRegister.class})
public class MainConfig { }
D、通过实现FacotryBean接口来实现组件注册。适用于要注册的组件初始化复杂时,因为可以在getObject中写逻辑来进行复杂的初始化,别的方法均不可
public class CarFactoryBean implements FactoryBean<Car> {
//返回bean的对象
@Override public Car getObject() throws Exception {
return new Car();
}
//返回bean的类型
@Override
public Class<?> getObjectType() {
return Car.class;
}
//是否为单利
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
public class MainConfig {
@Bean
public CarFactoryBean carFactoryBean(){
return new CarFactoryBean();
}
}
注意:此时正常通过组件名carFactoryBean获取到的其实是Car对象,要想获取
CarFactoryBean对象则通过组件名&carFactoryBean获取
3.2、自动装配注解:@AutoWired
//一个Dao
@Repository
public class TulingDao { }
@Service
public class TulingService {
@Autowired
private TulingDao tulingDao;
}
结论:自动装配首先是按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照属性名称来进行装配
扩展:
a、强制指定特定名字的组件进行装配:@Qualifier
@Autowired
@Qualifier("tulingDao")
private TulingDao tulingDao2;
b、没有相应组件便会抛出异常,如不想抛异常,则required = false
@Autowired(required = false)
@Qualifier("tulingDao")
private TulingDao tulingDao2;
3.3、给组件赋值注解
A、@Value
public class Person {
//通过普通的方式
@Value("司马")
private String firstName;
//spel方式来赋值
@Value("#{28-8}")
private Integer age;
//通过读取外部配置文件的值
@Value("${person.lastName}")
private String lastName;
}
B、@PropertySource
@Configuration
@PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置
public class MainConfig {
@Bean
public Person person() {
return new Person();
}
}
注意:person.properties中的属性要和person类中的属性一一对应
3.4、根据环境来激活不同的Bean注解:@Profile
@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效
@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活
没有标志为@Profile的bean 不管在什么环境都可以被激活
//标识为测试环境才会被装配
@Bean
@Profile(value = "test")
public DataSource testDs() {
return buliderDataSource(new DruidDataSource());
}
//标识为开发环境才会被激活
@Bean
@Profile(value = "dev")
public DataSource devDs() {
return buliderDataSource(new DruidDataSource());
}
扩展:切换环境的方法
a、通过运行时jvm参数来切换 -Dspring.profiles.active=test|dev|prod
b、通过代码的方式来激活
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("test","dev");
ctx.register(MainConfig.class);
ctx.refresh();
printBeanName(ctx);
}
4、 我们自己的组件 需要使用spring ioc的底层组件的时候,比如 ApplicationContext等,我们可以通过实现XXXAware接口来实现
@Component
public class TulingCompent implements ApplicationContextAware,BeanNameAware {
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
System.out.println("current bean name is :【"+name+"】");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
三、Spring AOP
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/153474.html