js css html

[java]44、Spring-04注解

2022-05-29  本文已影响0人  史记_d5da

1、拆分applicationContext.xml

分别创建applicationContext.xmlapplicationContext-mybatis.xml两个文件

1.1、在applicationContext.xml文件中通过标签导入实现

<import resource="applicationContext-mybatis.xml" />

1.2、在java中导入多个xml文件
ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "applicationContext.xml",
                                "applicationContext-mybatis.xml");
1.3、使用classpath*通配符
ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath*:applicationContext*.xml");
1.4、注解实现bean标签

applicationContext.xml设置需要扫描的包
<context:component-scan base-package="com.sj.domain" />
1、@Component
相当于<bean>,通过value设置beanid,默认会将类名的首字母小写形式作为beanid

import org.springframework.stereotype.Component;
@Component("person")
public class Person {
}

2、@Controller用于标识控制器层,@Service用于标识业务层等价于@Component@Repository用于标志Dao
3、@Scope:设置singletonprototype
@Lazyscopesingleton时延迟加载

<bean scope="singleton" lazy-init="true" />

4、@ComponentScan:相当于<context:component-scan />标签
@ComponentScans:扫描多个包
例如扫描service下面的包

import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
@Component("person")
@ComponentScans({
        @ComponentScan("com.sj.dao"),
        @ComponentScan("com.sj.servlet")
})
@ComponentScan("com.sj.service")
public class Person {
}

5、@Autowired:默认按照类型注入bean实例
可以写在成员变量(不会调用setter)、setter、构造方式上
可以配合使用@Qualifier@Named:设置需要注入的beanid
required设置为false:找不到对应的bean时不会抛出异常

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class User {
    private Dog dog;
    @Autowired(required = true) // 找不到dog2类型会抛异常
    @Qualifier("dog2") // 设置自动注入的类型名称是dog2
    public void setDog(Dog dog) {
        this.dog = dog;
    }
}

在有参构造方法中参数也会有注入值

@Component
public class User {
    private Dog dog;
    public User(Dog dog) { // 自动注入dog的值
        this.dog = dog;
    }
}

6、@Value
用于注入String、基本类型、BigDecimal等类型
可以配合配置文件(比如properties)使用${}读取配置文件的内容
7、@PropertySources@PropertySource
相当于<context:property-placeholder>

@Component("dog2")
@PropertySource("dog.properties")
@PropertySources({
        @PropertySource("user.properties")
})
public class Dog {
    private String name;
    @Value("${name}")
    public void setName(String name) {
        this.name = name;
    }
}

2、注解其他功能实现

2.1、注解实现AOP

@Aspect:用来标识一个切面类(切面类对象需要被放入到IoC容器中)
@Around:用来设置切入点(被注解的方法要有返回值、接收一个ProceedingJointPoint参数)
还需要加上标签<aop:aspectj-autoproxy>,代替之前的<aop:config>
同样有proxy-target-class属性设置AOP的底层实现方案
<aop:aspectj-autoproxy proxy-target-class="true" />
1、applicationContext.xml代码如下

<context:component-scan base-package="com.sj" />
<aop:aspectj-autoproxy />
// 初始化切面类
<bean class="com.sj.aop.DefaultAspect" />

注解指明需要切入的对象

@Aspect
public class DefaultAspect {
    @Around("within(com.sj.service.impl.UserServiceImpl)")
    public Object log(ProceedingJoinPoint point) throws Throwable{
        // 调用目标方法
        Object ret = point.proceed();
        return ret;
    }
}

2、或者使用@Pointcut配置切入点

@Aspect
public class DefaultAspect {
    @Pointcut("within(com.sj.service.impl.UserServiceImpl)")
    public void pc() { }
    @Around("pc()")
    public Object log(ProceedingJoinPoint point) throws Throwable{
        Object ret = point.proceed();
        return ret;
    }
}

applicationContext.xml中配置切入函数

<aop:config>
    <aop:pointcut id="pc" expression="com.sj.aop.DefaultAspect.pc()"/>
    <aop:advisor advice-ref="logInterceptor" pointcut-ref="pc" />
</aop:config>
2.2、注解实现事务管理

1、@Transactional
可以在需要进行事务管理的类(比如Service)上使用这个注解,代表所有方法都会自动管理事务
可以在需要进行事务管理的方法上使用这个注解(可以覆盖类中@Transactional的配置)
可以设置isolationpropagationtimeoutrollbackFornoRollbackForreadOnly等属性
2、使用<tx:annotation-driven/>取代之前的<tx:advice><aop:config>
同样有proxy-target-class属性设置AOP的底层实现方案

<tx:annotation-driven transaction-manager="txMgr" />
2.3、@Configuration@Bean

1、@Configuration:使用此注解的类,可以取代applicationContext.xml,将注解类添加到IoC容器中
它也是一个@Component,所以可以通过component-scan扫描

import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
}

2、可以在@Configuration类中,使用@Bean修饰方法,进行bean对象的创建
默认情况下,方法名就是beanid。也可以通过namevalue属性设置beanid
可以配置@Scope设置bean的创建次数

@Configuration
public class BeanConfig {
    @Bean("skill2")
    @Scope("prototype")
    public Skill skill() {
        return new Skill();
    }
}

3、@Bean方法的注入-bean
如果bean属性本身有@Autowired,那么直接new原来对象即可

// Dog
@Component
public class Dog {}
// Person
public class Person {
    private Dog dog;
    @Autowired
    public void setDog(Dog dog) { this.dog = dog  }
}
// BeanConfig
@Configuration
public class BeanConfig {
    @Bean
    public Person person(Dog dog) {
        return new Person();
    }
}

Spring会利用@Autowired技术,自动注入bean@Bean方法的参数

@Configuration
public class BeanConfig {
    @Bean // 默认@Scope("singleton") IoC 容器创建时就会创建对象
    public Dog dog() {  return new Dog();  }
    @Bean // 自动注入 Dog 的对象
    public Person person(Dog dog) {
        Person person = new Person();
        person.setDog(dog);
        person.setDog(dog()); // 调用多次,只new一个对象
        person.setDog(dog());
        return person;
    }
}

@Bean方法被直接调用多次,也能保证是singleton,因为@Configuration底层使用了CGLib动态代理,对@Bean方法进行了增强处理

// this指向的是代理对象
this = {BeanConfig$$EnhancerBySpringCGLIB$$6a559a7e@2260} 
dog = {Dog@2258} 
person = {Person@2259} "Person{dog=null}"
// 代理对象伪代码
public class BeanConfigCGLIB extends BeanConfig{
    @Override
    public Dog dog() {
        if (容器里没有) {
            return super.dog();
        } else {
            return 容器里的dog;
        }
    }
}

4、@Bean方法注入-FactoryBean
@Bean方法返回的是DogFactoryBean,由于@Configuration底层是用了CGLib@Bean进行了增强处理,会调用@BeangetObject方法

public class DogFactoryBean implements FactoryBean<Dog> {
    @Override
    public Dog getObject() throws Exception {
        return new Dog();
    }
    @Override
    public Class<?> getObjectType() {
        return Dog.class;
    }
}
@Configuration
public class BeanConfig {
    @Bean
    DogFactoryBean dog() {
        return new DogFactoryBean();
    }
}

5、@Bean的方法注入-其他类型

@Configuration
@PropertySource("person.properties")
public class BeanConfig {
    @Value("${age}")
    private int age;
    @Value("${name}")
    private String name;

    @Bean
    public Person person() {
        Person person = new Person();
        person.setAge(age);
        person.setName(name);
        return person;
    }
}

3、纯注解开发

3.1、工厂注解入口

如果创建的工厂入口是注解,一般就用AnnotationConfigApplicationContext
可以通过@Import@ComponentScan扫描其他注解信息
可以通过@ImportSource导入其他XML配置文件

new AnnotationConfigApplicationContext("com.mj")
new AnnotationConfigApplicationContext(Person.class)
@Import({Person.class, BeanConfig.class})
public class Dog {
}
public class SkillTest {
    public ApplicationContext ctx;
    @Before
    public void before() {
        ctx = new AnnotationConfigApplicationContext(Person.class);
    }
    @Test
    public void test() {
        System.out.println(ctx.getBean("com.mj.domain.Person"));
    }
}

通过@Import导入创建beanid是全类名

3.2、bean的创建方式总结

1、在Spring中,bean有3中常见的创建方式
@Component:常用于源码不可修改的类型(比如第三方库的类型)或者创建过程比较复杂的类型
@Bean:常用于源码不可修改的类型(比如第三方库的类型)或者创建过程比较复杂的类型
<bean>:适用于所有类型
当上述三种方式beanid类型相同时,优先级如下:
<bean>大于@Bean大于@Component
因为<bean>可以用于覆盖以前@Bean@Component的内容,所有减少@Bean@Component代码的变动

3.3、纯注解开发-AOP

@EnableAspectJAutoProxy相当于<aop:aspectj-autoproxy />

@Configuration
@EnableAspectJAutoProxy // 取代<aop:aspectj-autoproxy />
@ComponentScan("com.mj")
public class BeanConfig { }
3.4、纯注解开发-MyBatis

@MapperScan相当于MapperScannerConfigurer

// db.properties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test_mbatis
jdbc.username=root
jdbc.password=shijikl126

mybatis.typeAliasesPackage=com.mj.domain
mybatis.mapperLocations=mappers/*.xml
mybatis.mapperScan=com.mj.dao
@Configuration
@PropertySource("db.properties")
@MapperScan("${mybatis.mapperScan}")
public class MyBatisConfig {
    @Value("${jdbc.driverClass}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${mybatis.typeAliasesPackage}")
    private String typeAliasesPackage;
    @Value("${mybatis.mapperLocations}")
    private String mapperLocations;
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage(typeAliasesPackage);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        return bean;
    }
}
3.5、纯注解开发- 事务管理

@EnableTransactionManagement相当于<tx:annotation-driven />

@Configuration
@EnableTransactionManagement
public class TxConfig {
    @Bean
    public DataSourceTransactionManager mgr(DataSource dataSource) {
        DataSourceTransactionManager mgr = new DataSourceTransactionManager();
        mgr.setDataSource(dataSource);
        return mgr;
    }
}
3.6、JSR注解

1、JSRJava Specification Requests的缩写,译为Java规范提案

2、Spring也支持JSR规范中定义的注解
3、需要导入的依赖

<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>javax.activation-api</artifactId>
    <version>1.2.0</version>
</dependency>

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

3、@Resource@Inject

public Person() {
    System.out.println("Person-----------------");
}
@Inject
public Person(@Named("dog2") Dog dog, @Value("jack") String name) {
    this.dog = dog;
    this.name = name;
    System.out.println("Person(dog, name)-----------------");
}

4、@PostConstructor@PreDestory
@PostConstructor:在InitializingBean的afterPropertiesSet方法之前调用
@PreDestory:在DisposableBeandestroy方法之前调用
上述两个注解替代的方法是init-methoddestroy-method

@PostConstruct
public void postConstrut() {}
@PreDestroy
public void preDestory() {}
3.7、property-placeholder的底层

它的底层使用了PropertySourcesPlaceholderConfigurer
可以使用这个类取代<context:property-placeholder />@PropertySources@PropertySource

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="location" value="db.properties" />
</bean>
@Bean
    public PropertySourcesPlaceholderConfigurer configurer() {
    PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    configurer.setLocation(new ClassPathResource("db.properties"));
    return configurer;
}
3.8、component-scan详解

exclude-filter:设置不需要扫描的类型
include-filter:设置需要扫描的类型

<context:component-scan base-package="com.sj" >
    <context:exclude-filter type="assignable" expression="com.sj.domain.Dog"/>
    <context:include-filter type="assignable" expression="com.sj.domain.Person"/>
    <context:exclude-filter type="aspectj" expression="com.sj.service..*"/>
    <context:exclude-filter type="regex" expression=".*er.*"/>
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

include-filter包含的类型,就算没有@Component<bean>@Bean修饰,也会放到IoC容器中

关于exclude-filterinclude-filtertype属性值,决定了expression属性可以设置什么值
assignable:设置具体类型
annotation:设置注解类型
aspectj:设置切入点表达式within中的内容
regex:设置正则表达式,比如.*service.*表示全类名中包含service
custom设置自定义类型过滤器(实现org.springframework.core.type.filter.TypeFilter接口)

<context:exclude-filter type="custom" expression="com.sj.filter.MyTypeFilter"/>
// MyTypeFilter.java
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader,
                          MetadataReaderFactory metadataReaderFactory) throws IOException {
        System.out.println(metadataReader.getClassMetadata().getClassName());
        String name = metadataReader.getClassMetadata().getClassName();
        return name.matches(".*My.*"); // 过滤带有My字符的
    }
}
3.9、@CommponentScan
@Component
@ComponentScan(basePackages = "com.sj", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Person.class, Dog.class}),
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Service.class),
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class),
        @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*My.*"),
        @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.sj.service..*"),
})
public class MyCar {
}
上一篇下一篇

猜你喜欢

热点阅读