# Spring注解版
## 一、@Configuration和@Bean注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public class Person { private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this .name = name; this .age = age; } public String getName() { return name; } public void setName(String name) { this .name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this .age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\ '' + ", age=" + age + '}' ; } } |
配置类:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Configuration public class ApplicationConfig { @Bean public Person person(){ return new Person( "lisi" , 18 ); } /*@Bean("person02") public Person person(){ return new Person("lisi",20); }*/ } |
对比配置文件:
<?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.wzs.entity.Person"> <property name="name" value="zs"/> <property name="age" value="18"/> </bean> </beans>
1.@Configuration:标注在类上,则表明该类是一个配置类,作用类似xml。
2.@Bean:
1)标注在方法上,则表明注册一个组件到ioc容器中。
2)方法的返回值类型代表要注册到容器的类型,代表bean中的class
3)方法名代表注册到ioc的bean的id
4)@Bean写上字符串则可以该表bean的id
配置类测试:
public class ConfigTest { public static void main(String[] args) { ApplicationContext ioc = new AnnotationConfigApplicationContext(ApplicationConfig.class); Person bean = ioc.getBean("person"); System.out.println(bean);//Person{name='lisi', age=18} } }
## 二、@ComponentScan注解
1.@ComponentScan注解作用类似于xml中的<context:component-scan>标签,即作用是包扫描。
2.该注解写在配置类上
3.格式:@ComponentScan(value = "指定要扫描的包名")
4.配置包扫描的规则:
1)excludeFilters:排除
配置类方式:
@ComponentScan(value ="com.wzs" ,excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class) }) //excludeFilters:表示排除规则 //type:指定排除的类型 //value:指定排除的具体类型
xml方式:
<context:component-scan base-package="com.wzs"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
2)includeFilters:只包含 注意使用时还要加上useDefaultFilters =false来禁用默认规则
配置类的方式:
@ComponentScan(value ="com.wzs" ,includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class) },useDefaultFilters =false ) //includeFilters:表示只包含规则 //type:指定包含的类型 //value:指定包的具体类型
xml方式:
<context:component-scan base-package="com.wzs" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
3)@ComponentScan.Filter的type:指定类型
type可以取的值有:
FilterType.ANNOTATION;(掌握):代表扫描带有注解的
FilterType.ASSIGNABLE_TYPE;(掌握):代表扫描指定类的
FilterType.ASPECTJ;
FilterType.REGEX;
FilterType.CUSTOM;(掌握):代表扫描自定义规则类的
FilterType.ASSIGNABLE_TYPE:
@ComponentScan(value ="com.wzs" ,includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = com.wzs.service.MyService.class) },useDefaultFilters =false )
FilterType.CUSTOM:
使用FilterType.CUSTOM前提是要写自定义规则的类,且该类要实现TypeFilter接口:
public class Myfilter implements TypeFilter { @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { //获取扫描当前类的注解信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //获取当前正在扫描类的信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前正在扫描类的资源路径 Resource resource = metadataReader.getResource(); //获取扫描类的全类名 String className = classMetadata.getClassName(); //将指定的类加载到ioc容器中 if(className.contains("er")){ return true; } return false; } } // return true;加入到容器 //return false;不加入到容器
@ComponentScan(value ="com.wzs" ,includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,value = com.wzs.filter.Myfilter.class) },useDefaultFilters =false )
本例详解:由于指定的包为“com.wzs",故会扫描该包下的所有类,因此该包下的所有类都会被com.wzs.filter.Myfilter.class处理,如果类名包含”er“,则加入到ioc容器,否则不加入到ioc容器
## 三、@Scope注解
前景:无论是xml方式加入组件到ioc容器,还是通过注解的方式加入组件到ioc容器,这些组件默认都是单实例的。
1.@Scope注解用在带有@Bean的标签上
2.@Scope注解的取值有:prototype(多实例的)、singleton(单实例的)
配置类的方式给组件赋予单实例或多实例:
@Scope("singleton") @Bean public Person person(){ return new Person("lisi",18); } @Scope("prototype") @Bean public Person person(){ return new Person("lisi",18); }
xml的方式给组件赋予单实例或多实例:
<bean id = "person" class="com.wzs.entity.Person" scope="singleton" > <property name="name" value="zs"/> <property name="age" value="18"/> </bean> <bean id = "person" class="com.wzs.entity.Person" scope="prototype" > <property name="name" value="zs"/> <property name="age" value="18"/> </bean>
无论是xml还是配置文件的方式:
单实例的对象创建是在容器启动的时候创建。
多实例的对象创建是在每次获取到该实例的时候创建。
## 四、@Lazy注解
前景:懒加载针对的是单实例的bean,容器启动的时候不创建对象,第一次获取bean时加载.
使用:写在@bean方法之上
配置类的形式:
@Lazy @Bean public Person person(){ return new Person("lisi",18); }
xml的形式:
<bean id = "person" class="com.wzs.entity.Person" lazy-init = "true" > <property name="name" value="zs"/> <property name="age" value="18"/> </bean>
## 五、@Conditional注解
写法:写在@Bean方法或@Configuration类之上。
作用:按照一定的条件,注册指定的bean。其实也类似@ComponentScan中的过滤规则。
使用:
1.创建一个实现了Condition接口的类:
public class MyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("os.name"); if(property.contains("Linux")){//如果当前的操作系统是Linux系统,则将加入到ioc容器中 return true; } return false; } }
2.加@Conditional注解
@Conditional(MyCondition.class) @Bean public Person person(){ return new Person("lisi",18); }
## 六、@Import注解
@Import注解的作用:导入指定的类到容器中
单个导入类到容器中,默认id是全类名:
@Import(com.wzs.dao.MyDao.class) @Configuration public class ApplicationConfig { }
批量导入类到容器中,默认id是全类名:
方式一:
首先实现ImportSelector接口
public class MySelector implements ImportSelector { //返回的数组封装了加载到ioc容器组件 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.wzs.service.MyService"}; } }
然后:
@Import(com.wzs.condition.MySelector.class) @Configuration public class ApplicationConfig { }
方式二:
首先实现ImportBeanDefinitionRegistrar接口:
public class MyDefiniton implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { RootBeanDefinition bean = new RootBeanDefinition(Person2.class);//注册一个bean registry.registerBeanDefinition("person2",bean);//注册到ioc容器中,第一参数指定bean的id,第二个参数指定注册的bean } }
然后:
@Import(com.wzs.condition.MyDefiniton.class) @Configuration public class ApplicationConfig { }
===================================================================================================================================
方式三、
导入单个bean到ioc容器中:
首先实现FactoryBean<Person>接口:
public class MyFactory implements FactoryBean<Person> { //返回一个对象并加入到ioc容器中 @Override public Person getObject() throws Exception { return new Person("wzs",22); } //类型 @Override public Class<?> getObjectType() { return Person.class; } //是否单例 @Override public boolean isSingleton() { return true; } }
@Configuration public class ApplicationConfig { @Bean public MyFactory myFactory(){ return new MyFactory(); } }
public static void main(String[] args) { ApplicationContext ioc = new AnnotationConfigApplicationContext(ApplicationConfig.class); Object bean = ioc.getBean("myFactory"); System.out.println(bean.getClass());//class com.wzs.entity.Person类型 //如果就是想要工厂对象的话 Object bean = ioc.getBean("&myFactory"); System.out.println(bean.getClass()); //class com.wzs.condition.MyFactory }
## 七、bean的生命周期
1.bean的生命周期:
bean创建 --》 初始化 ---》销毁
2.容器管理bean的生命周期:
我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候调用我们的初始化和销毁方法。
3.具体步骤:
方式一:用@Bean注解,指定初始化和销毁方法
1)自定义初始化和销毁方法
public class User { private int id; private String name; public User() { System.out.println("无参构造方法"); } public User(int id, String name) { this.id = id; this.name = name; System.out.println("有参构造方法"); } public void init(){ System.out.println("初始化方法"); } public void destroy(){ System.out.println("销毁方法"); } }
2)指定初始化和销毁方法
@Bean(initMethod = "init",destroyMethod = "destroy") public User user(){ return new User(); }
整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁
方式二:实现InitializingBean, DisposableBean接口
1)重写初始化和销毁方法:
public class Goods implements InitializingBean, DisposableBean { public Goods(){ System.out.println("构造方法Goods()"); } @Override public void destroy() throws Exception { System.out.println("销毁方法destroy()"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("初始化方法afterPropertiesSet()"); } }
整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁
方式三:使用jsr250中的注解:
@PostConstruct:在bean创建完成并属性赋值完成后执行的初始化方法。
@PreDestroy:在容器销毁bean之前通知进行的清理工作。
public class Animal { public Animal(){ System.out.println("构造方法Animal()"); } @PostConstruct public void init(){ System.out.println("初始化方法init()"); } @PreDestroy public void destroy(){ System.out.println("销毁方法destroy()"); } }
@Bean public Animal animal(){ return new Animal(); }
整个调用的过程:构造器 --》初始化 --》容器关闭 --》销毁
方式四:实现BeanPostProcessor接口,为【所有bean】【初始化方法】【前后】调用的方法
//bean的后置处理器 public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("bean的名字"+beanName+":postProcessBeforeInitialization"); return bean ; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("bean的名字"+beanName+":postProcessAfterInitialization"); return bean; } }
@Configuration public class ApplicationConfig { @Bean public Animal animal(){ return new Animal(); } public MyBeanPostProcessor myBeanPostProcessor(){ return new MyBeanPostProcessor(); } }
整个调用的过程:构造器 --》postProcessAfterInitialization--》初始化 --》postProcessAfterInitialization--》容器关闭 --》销毁。
即使没有初始化和销毁方法,这些方法也会依次被执行
## 八、@Value注解
@Value的用法,给属性赋值:
1.基本数值 2.可以写SpEl表达式:#{} 3.可以写${},取出配置文件的值,但是要结合@PropertySource注解
1)对于第三种方式读取配置文件的值需要先加载配置文件,然后才能读取:
2)@PropertySource(value = {"classpath:/application.properties"}) value指定配置文件的位置;这种方法类似xml中引入外部配置文件<context:property-placeholder location="classpath:application.properties"/>.
3)此外还要说的是@Value方式给bean赋值,是通过Setter方法的方式进行赋值的。
## 九、自动装配
### 1.spring规范的@Autowire自动装配:
@Autowire:自动装配 默认首先按照类型自动装配,如果ioc容器中存在多个类型,则按照属性名作为id自动装配;
如果想要装配指定的bean,则【额外】还要加上@Qualifer("id名")进行装配;
默认自动装配一定要装配上的,那么我们可以修改默认值,如果装配不上,则装配null,方法是@Autowire(required=falue)
@Primary指定默认装配首选装配的bean,这样自动装配的时候,首选装配用@Primary修饰的bean;
### 2.java规范的@Resouce和@Inject自动装配:
@Resource注解:自动装配默认按照属性名作为id进行自动装配,不支持required=false和@Primary功能;
当然@Resource(“id名”)指定要装配的bean。
@Inject注解:使用该注解需要导入javax.inject的jar;自动装配 默认首先按照类型自动装配,如果ioc容器中存在多个类型,则按照属性名作为id自动装配;支持@Primary,但不支持required=false。
## 十、针对@Autowire
@Autowire可以标注的位置有:属性、方法、构造器、参数上。
1)标注在类普通方法上:
ioc容器创建该bean时,会自动调用用@Autowire标注的方法,并且为该方法上所有参数(引用类型)进行自动装配;
如果在配置类的方式上将bean加入到ioc容器中,如果加入该bean的方法上存在参数,则也会自动装配。
@Bean public Person person(User user){//User user会自动被装配上 return new Person(); }
2)标注在构造器上:
ioc容器创建该bean时,会优先用@Autowird修饰的构造方法创建bean,并为该构造方法的所有参数(引用类型)进行自动装配。
注意:自动装配默认一定要装配上。
## 十一、Aop的使用
1.创建一个被切面切的逻辑处理类
package com.wzs.service; /** * * Created by wzs on 2020/8/23 **/ public class Calculator { public int addition(int a,int b){ return a+b; } public int substruction(int a,int b){ return a-b; } public int multiplication(int a,int b){ return a-b; } public int division(int a,int b){ return a-b; } }
2.创建一个切面类
package com.wzs.config; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import java.util.Arrays; /** * * Created by wzs on 2020/8/23 **/ @Aspect public class LogUtils { @Pointcut("execution(public int com.wzs.service.Calculator.*(..))") public void poinCut(){} @Before(value = "poinCut()") public void logBefore(JoinPoint joinPoint){ Object[] args = joinPoint.getArgs(); System.out.println(joinPoint.getSignature().getName()+"方法运行,@before:参数列表:{"+ Arrays.asList(args)+"}"); } @AfterReturning(value = "poinCut()",returning = "result") public void logAfterReturning(JoinPoint joinPoint,Object result){ System.out.println(joinPoint.getSignature().getName()+"方法运行,@AfterReturning:结果:{"+ result+"}"); } @AfterThrowing(value = "poinCut()",throwing = "e") public void logAfterThrowing(JoinPoint joinPoint,Exception e){ System.out.println(joinPoint.getSignature().getName()+"方法运行,@AfterReturning:异常原因:{"+ e.getCause()+"}"); } @After(value = "poinCut()") public void logAfter(JoinPoint joinPoint){ System.out.println(joinPoint.getSignature().getName()+"方法运行,@After:"); } }
3.将被切和切的类加入到容器,同时开启注解的aop模式@EnableAspectJAutoProxy
package com.wzs.config; import com.wzs.service.Calculator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * * Created by wzs on 2020/8/23 **/ @EnableAspectJAutoProxy //开启注解形式的aop 类似 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> @Configuration public class AopConfig { @Bean public Calculator calculator(){ return new Calculator(); } @Bean public LogUtils logUtils(){ return new LogUtils(); } }
## 十一、声明式事务
1.写事务,添加@Transactional
public class TxService { @Autowired JdbcTemplate jdbcTemplate; @Transactional public void insert(){ String sql = "insert into admin(username,password) values(?,?)"; String substring = UUID.randomUUID().toString().substring(0, 5); jdbcTemplate.update(sql,substring,123456); System.out.println("插入成功"); int a = 1/0; } }
2.配置,添加@EnableTransactionManagement
package com.wzs.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* * Created by wzs on 2020/8/23
**/
@EnableTransactionManagement//开启注解事务,类似xml中的 <tx:annotation-driven transaction-manager = "tm"/>
@Configuration
@Import(com.wzs.service.TxService.class)
public class TxConfig {
@Bean
public DataSource dataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/girls");
dataSource.setUser("root");
dataSource.setPassword("123456");
return dataSource;
}
@Bean
public JdbcTemplate template() throws Exception {
return new JdbcTemplate(dataSource());
}
//配置事务管理器,控制数据源
public PlatformTransactionManager platformTransactionManager() throws Exception {
return new DataSourceTransactionManager(dataSource());
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)