Spring注解版
一、@Configuration和@Bean注解
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 +
'}';
}
}
配置类:
@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>
4)@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接口:
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注解
对于第三种方式读取配置文件的值需要先加载配置文件,然后才能读取:
@PropertySource(value = {“classpath:/application.properties”}) value指定配置文件的位置;这种方法类似xml中引入外部配置文件<context:property-placeholder location=“classpath:application.properties”/>.
此外还要说的是@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可以标注的位置有:属性、方法、构造器、参数上。
标注在类普通方法上:
ioc容器创建该bean时,会自动调用用@Autowire标注的方法,并且为该方法上所有参数(引用类型)进行自动装配;
如果在配置类的方式上将bean加入到ioc容器中,如果加入该bean的方法上存在参数,则也会自动装配。
@Bean
public Person person(User user){//User user会自动被装配上
return new Person();
}
标注在构造器上:
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());
}
}