美文网首页js css html
[java]44、Spring-04注解

[java]44、Spring-04注解

作者: 史记_d5da | 来源:发表于2022-05-29 12:47 被阅读0次

    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规范提案

    • 是指向JSP(Java Community Process)提出新增一个标准化技术规范的正式请求,任何人都可以提交JSR,以向Java平台增添新的API和服务
    • 一旦某个JSR通过了JCP的审核,他就变成了Java技术栈的一部分,可以安全第用于生成环境
    • JSR审核过程确保了只有可靠稳定的技术才能变成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

    • @Resource:根据名称进行注入,可以在成员变量setter
      @Resource(name = "dog")等价于@Autowired@Qualifier("dog")
    • @Inject:默认根据类型进行注入,可以用在成员变量、setter、构造方法上
      可以配合使用@Qualifier@Name:设置需要注入的beanid
    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 {
    }
    

    相关文章

      网友评论

        本文标题:[java]44、Spring-04注解

        本文链接:https://www.haomeiwen.com/subject/yglkprtx.html