1 组件添加
@Configuration:将spring中的配置文件写成配置类,用此注解表明配置类的身份
@Configuration
@Import({Color.class,
MyImportSelect.class,
MyImportBeanDefinitionRegistrar.class})
public class MyConfig {
@Bean("book")
public Book book2(){
return new Book("小王子",20.0);
}
@Conditional(value = { WindowCondition.class })
@Bean("bill")
public Person person1(){
return new Person("Bill Gates",62);
}
@Conditional(value = { LinuxCondition.class })
@Bean("linus")
public Person person2(){
return new Person("linus",48);
}
@Bean("colorFactoryBean")
public ColorFactoryBean getColor(){
return new ColorFactoryBean();
}
}
@ComponentScan:包扫描
相当于xml中的:
<context:component-scan base-package="包名">
</context:component-scan>
用法为:
@ComponentScan(value={"包名"},includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.CUSTOM,classes={MyFilter.class})
},useDefaultFilters=false)
useDefaultFilters=false:将默认过滤关闭
//扫描该包名下除了用Controller注解标注的类
@ComponentScan(value={"包名"},excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
FilterType.ANNOTATION:注解类型
FilterType.CUSTOM:自定义过滤类,该类实现TypeFilter接口
@Bean:配置类中方法上添加该注解,将方法返回的对象添加到ioc容器中
@Scope("prototype")
@Bean("book")
public Book book(){
return new Book("小王子",20.0);
}
bean的延伸知识:
- 构建(对象创建):
单实例:在容器启动的时候创建对象
多实例:在每次获取的时候创建对象 - 初始化:
对象创建完成,并赋值好,调用初始化方法… - 销毁:
单实例:容器关闭的时候
多实例:容器不会管理这个bean,并且不会调用销毁方法
指定初始化和销毁方法:
- 通过@Bean指定initMethod和destroyMethod
@Bean(value="car",initMethod="init",destroyMethod="destory")
public Car car(){
return new Car();
}
public class Car {
public Car() {
System.out.println("car constructor..");
}
private void init() {
System.out.println("car init..");
}
private void destory() {
System.out.println("car destory..");
}
}
- bean实现InitializingBean接口(初始化方法)
DisposableBean接口(销毁方法)
@Component
public class Cat implements InitializingBean,DisposableBean{
public Cat() {
// TODO Auto-generated constructor stub
System.out.println("cat construst...");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat afterPropertiesSet...");
}
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("cat destory...");
}
}
- 使用JSR250:
@PostConstruct:在bean创建完成并且属性赋值完成后执行初始化方法
@PreDestroy:在容器销毁bean之前通知我们进行清理工作
@Component
public class Dog {
public Dog() {
System.out.println("Dog construct...");
}
@PostConstruct//在对象创建完成并且属性完成之后执行
private void init() {
System.out.println("dog init...");
}
@PreDestroy//容器销毁bean之前执行此方法
private void destory() {
// TODO Auto-generated method stub
System.out.println("dog destory...");
}
}
- BeanPostProcessor接口:bean的后置处理器在bean初始化前后进行一些处理工作
postProcessBeforeInitialization:在初始化之前工作
postProcessAfterInitialization:在初始化之后工作
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor() {
System.out.println("---------MyBeanPostProcessor construct---------");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("<--"+beanName+" postProcessBeforeInitialization-->");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(">--"+beanName+" postProcessAfterInitialization--<");
return bean;
}
}
@Scope:是springIoc容器中的一个作用域,默认为single
基本作用域singleton(单例)、prototype(多例),Web 作用域(reqeust、session、globalsession),自定义作用域
@Condition:按照一定的条件进行判断,满足判断的bean进行注册
@Conditional(value = { WindowCondition .class })
@Bean("bill")
public Person person1(){
return new Person("Bill Gates",62);
}
public class WindowCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文环境
* AnnotatedTypeMetadata:注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO Auto-generated method stub
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println(property);
if(property.contains("Window")){
return true;
}
return false;
}
}
@Import:快速给容器中导入一个组件,标注在配置类上
@Configuration
@Import({Color.class,
MyImportSelect.class,
MyImportBeanDefinitionRegistrar.class})
MyImportSelect:返回需要导入的组件的全类名数组,实现ImportSelector接口
public class MyImportSelect implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// TODO Auto-generated method stub
return new String[]{"com.atguigu.bean.Red","com.atguigu.bean.Blue"};//方法不要返回NULL,可以返回空数组
}
}
MyImportBeanDefinitionRegistrar:手动注册bean到容器中,实现ImportBeanDefinitionRegistrar接口
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// TODO Auto-generated method stub
boolean containsBeanDefinition = registry.containsBeanDefinition("全类名");
boolean containsBeanDefinition2 = registry.containsBeanDefinition("全类名");
if(containsBeanDefinition && containsBeanDefinition2){
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(类名.class);
registry.registerBeanDefinition("对象名", rootBeanDefinition);
}
}
}
总结
给容器中注册组件的几种方式:
- 包扫描(@ComponentScan)+组件标注注解(@Controller+@Respository+@Service+@Component)
- @bean (导入第三方包里面的组件)
- @Import(快速给容器中导入一个组件):
@Import(要导入到容器中的组件):容器中就会自动注册这个组件,id默认为全类名
@ImportSelector:返回需要导入的组件的全类名数组
@ImportBeanDefinitionRegistrar:手动注册bean到容器中 - 使用Spring提供的FactoryBean(工厂bean)
默认获取到的是工厂bean调用getObject()创建的对象
若想获取工厂bean本身,需要给id前加一个&
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
2 组件赋值
@Value:使用此注解为属性赋值
- 1)基本数值:@Value(“字面量”)
- 2)可以写SpEL #{}:@Value("#{}")
- 3)可以取配置文件中的值,在运行环境里的值 ${}:@Value("${}")
@Autowired:自动为组件属性赋值
- 1)默认按照类型去容器中找对应组件
- 2)如果按照多个相同类型的组件,在按照属性的名称作为组件id去容器中查找
- 3)@Qualifier(""):指定需要装配的组件id,而不是使用属性名
- 4)自动装配默认必须将属性赋值,否则会报错,但可以用@Autowired(required=false)更改
- 5)@Primary:默认自动装配时首先装配该bean,但是如果写了@Quanlifier("")就按照指定的bean装配,配置在@Bean注解处
@Qualifier:使用此注解指定需要装配的组件id
@Primary:默认自动装配时首先装配该bean
@Resource:加载外部配置文件
可以和@Autowired一样实现自动装配功能,默认按照组件名称进行装配,不能支持@Primary功能和@Autowired(required=false)功能
@Inject:加载外部配置文件
需要导入javax.inject的包。和@Autowired的功能一样,没有required=false的功能
@PropertySource:加载外部配置文件
@PropertySource({"classpath:person.properties"})
@Profile:指定组件在哪个环境下才能被注册到容器中,不指定,任何环境下都能注册这个组件
- 1)加了环境标识的bean,只有这个环境才被激活的时候才能注册到容器中。默认是default环境
- 2)写在配置类上,只有是指定环境的时候,整个类里面的配置才能开始生效
- 3)没有标注环境标识的bean在任何环境下都是加载的
@Configuration
@PropertySource("classpath:/dbconfig.properties")
public class MyConfig5 {
@Value("${db.user}")
private String user;
@Value("$(db.driverClass)")
private String driverClass;
@Profile("test")
@Bean("test")
public DataSource dataSourcetest(@Value("$(db.password)")String password) throws PropertyVetoException{
ComboPooledDataSource datasource = new ComboPooledDataSource();
datasource.setUser(user);
datasource.setPassword(password);
datasource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
datasource.setDriverClass(driverClass);
return datasource;
}
@Profile("dev")
@Bean("dev")
public DataSource dataSourcedev(@Value("$(db.password)")String password) throws PropertyVetoException{
ComboPooledDataSource datasource = new ComboPooledDataSource();
datasource.setUser(user);
datasource.setPassword(password);
datasource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
datasource.setDriverClass("com.mysql.jdbc.Driver");
return datasource;
}
@Profile("prod")
@Bean("prod")
public DataSource dataSourceprod(@Value("$(db.password)")String password) throws PropertyVetoException{
ComboPooledDataSource datasource = new ComboPooledDataSource();
datasource.setUser(user);
datasource.setPassword(password);
datasource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
datasource.setDriverClass(driverClass);
return datasource;
}
}
如何激活?
命令行:-Dspring.profiles.actice=激活的环境名
或代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.getEnvironment().setActiveProfiles("test");
applicationContext.register(MyConfig5.class);
applicationContext.refresh();
String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
for(String beanName:beanNamesForType){
System.out.println(beanName);
}
applicationContext.close();
3 AOP
指在程序运行期间动态将某段代码切入到指定位置进行运行的编程方式
@Aspect:告诉Spring哪个是切面类
@EnableAspectJAutoProxy:加在配置类上,表示开启基于注解的aop模式
xml模式为:
<!-- 开启Aspectj的自动代理 -->
<aop:aspectj-autoproxy/>
@Configuration
@EnableAspectJAutoProxy
public class MyConfig{
//业务逻辑加入容器中
@Bean
public MyCalculator myCalculator (){
return new MyCalculator();
}
//切面类加入容器中
@Bean
public MyAspect myAspect(){
return new MyCalculator();
}
}
@PointCut:切入点表达式
@Pointcut(value="execution(* com.aop.aspectj.*.*(..))")
public void pointCut(){}
@Before:前置通知,在目标方法运行之前运行
@Before(value="pointCut()")
public void before(JoinPoint point){
System.out.println("执行方法:"+point.getSignature().getName()+",参数为:"+point.getArgs());
}
@After:后置通知,在目标方法运行之后运行(无论方法是否正常结束)
@After(value="pointCut()")
public void finallys(){
System.out.println("finally");
}
@AfterReturning:返回通知,在目标方法正常返回之后运行
@AfterReturning(value="pointCut()",returning="result")
//JoinPoint point参数只能写在第一个参数的位置
public void after(JoinPoint point,Object result){
System.out.println("方法 "+point.getSignature().getName()+" 执行结果为:"+result);
}
@AfterTrowing:异常通知,在目标方法出现异常以后运行
@AfterThrowing(value="pointCut()",throwing="ex")
public void throwing(Exception ex){
System.out.println(ex);
}
@Around:动态代理,手动推进目标方法运行
joinPoint.procced()
总结
1 将业务逻辑组件和切面类加入到容器中,告诉容器哪个是切面类(@Aspect)
2 在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3 开启基于注解的aop模式:@EnableAspectJAutoProxy
4 声明式事务
@Configuration
@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
public class MyConfigTx {
@Bean
public DataSource dataSource() throws PropertyVetoException{
ComboPooledDataSource datasource = new ComboPooledDataSource();
datasource.setUser("root");
datasource.setPassword("a");
datasource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
datasource.setDriverClass("jdbc:mysql://localhost:3306/test");
return datasource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
//Spring对@Configuration类会特殊处理,给容器中加组件的方法,多次调用都只是从容器中取组件
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
//配置事务管理器来控制事务
@Bean
public PlatformTransactionManager transactionManager() throws PropertyVetoException{
return new DataSourceTransactionManager(dataSource());
}
}
@Service
public class UserService{
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
//otherDao.other();
int i = 10 / 0;
}
}
@Repository
public class UserDao(){
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "";
jdbcTemplate.update(sql,args);
}
}
@Test
public void test(){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext (MyConfigTx .class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
applicationContext.close();
}
总结
- 导入相关依赖:数据源、数据库驱动、Spring-jdbc模块
- 配置数据源、JdbcTemplate操作数据
- @Transactional 给方法上标注此注解表示当前方法是一个事务方法
- @EnableTransactionManagement 开启基于注解的事务管理功能
- 配置事务管理器来控制事务