[Spring from entry to actual combat tutorial] Chapter 4 Detailed Explanation of Spring Annotation Development

4. Spring annotation development

    The stages experienced by the JavaWeb project:
        1. Servlet + JSP / Servlet + template engine. There are very few XML configurations at this stage, but it needs to be written from the basic code;
        2. SSH (Spring/Struts2/Hibernate) / SSM (Spring/SpringMVC/Mybatis ), this stage does not need to start from the basic code, but requires a lot of XML configuration;
        3, SSM, this stage does not need to start from the basic code, using annotation + XML configuration;
        4, SpringBoot, zero configuration (XML), using annotation + yml configuration;

4.1 Overview

    Starting from Java 5, Java has added support for annotations (Annotation), which is a special mark in the code, which can be read during compilation, class loading and runtime, and perform corresponding processing. Developers can embed supplementary information in source code without changing the original code and logic through annotations.

    Spring is an indispensable framework for development. Traditional xml-based configuration is too cumbersome. Spring has provided full support for annotation technology since version 2.5. We can use annotations to achieve automatic assembly and simplify Spring's XML configuration.

4.1.1 Xml advantages and disadvantages

advantage:

  • Reduce the coupling between classes, easy to modify, and easy to expand;

  • Easy to interact with other systems for data;

  • The relationship between objects is clear at a glance;

shortcoming:

  • The configuration is lengthy and requires additional maintenance, which affects development efficiency;

  • The type is not safe, it cannot be verified, and it is difficult to troubleshoot errors;

4.1.2 Advantages and disadvantages of annotations

advantage:

  • Simplified configuration;

  • It is intuitive and easy to use, improving the efficiency of development;

  • Type safety, easy to detect problems;

shortcoming:

  • It is more troublesome to modify than xml;

  • If you don't understand the project, it may cause trouble for development and maintenance;

A brief summary of the annotation: it is relatively simple and convenient to write, and it looks concise, but it is troublesome to modify;

Summary of Xml configuration: it is more flexible to write and easy to modify, but it is troublesome to write and maintain;

4.2 Open annotations

4.2.1 Component scanning

    Spring does not use annotations to assemble beans by default, so we need to enable the automatic scanning function of Spring Beans through the <context:component-scan> element in Spring's XML configuration. After enabling this function, Spring will automatically scan all classes under the specified package (base-package attribute setting) and its subpackages. If the @Component annotation is used on the class, the class will be assembled into the container.

  • Component scanning (component scanning): Spring can automatically scan from the classpath, detect and instantiate components with specific annotations, and make the annotations in Spring take effect;

  • For scanned components, Spring has a default naming rule: use the class name with lowercase initials as the default bean name, or identify the component name in the annotation through the value attribute value;

  • Declare tags in the Spring configuration file <context:component-scan>to implement component scanning;

  • <context:component-scan>The base-package attribute of the tag specifies a base class package that needs to be scanned, and the Spring container will scan all classes in the base class package and its sub-packages;

  • When multiple packages need to be scanned, commas can be used to separate them; or multiple <context:component-scan>tags can be configured;

<!-- 组件扫描 -->
<context:component-scan base-package="com.newcapec.bean"/>
<context:component-scan base-package="com.newcapec.dao"/>
<context:component-scan base-package="com.newcapec.service"/>
<context:component-scan base-package="com.newcapec.controller"/>

<!-- 上述写法可以简化为 -->
<context:component-scan base-package="com.newcapec"/>

Note: Before using <context:component-scan>the element to enable the auto-scanning function, you first need to add context-related constraints in the first-level tag <beans> of the XML configuration.

4.2.2 Scan filtering

  • 4.2.2.1 Coarse-grained filtering

If you only want to scan specific classes instead of all classes under the base package, you can use the resource-pattern attribute to filter specific classes:

<!-- 粗粒度过滤 -->
<context:component-scan base-package="com.newcapec" resource-pattern="bean/*.class"/>
  • 4.2.2.2 Fine-grained filtering

Sublabels can be used <context:include-filter>to denote target classes to include and <context:exclude-filter>to denote target classes to exclude. Among them, the type attribute has the following five types (the first two are mainly used):

  1. annotation: The filter scans those classes marked with annotations, and specifies the annotations to be scanned through the expression attribute;

  2. assignable: the filter scans those classes derived from the type specified by the expression attribute;

  3. aspectj: The filter scans those classes that match the AspectJ expression specified by the expression attribute;

  4. regex: The name of the filter scan class matches those classes specified by the regular expression specified by the expression attribute;

  5. custom: Use a custom org.springframework.core.type.TypeFliter implementation class, which is specified by the expression attribute

Note: If you use <context:include-filter>to filter the scanned content, you must set use-default-filters="false", otherwise it will fail and be overwritten by the default filtering mechanism. In the case of use-default-filters="false", exclude-filter excludes the content in include-filter.

Does not contain:

@Component
public class Dog {
    @Override
    public String toString() {
        return "Dog";
    }
}

//演示派生排除时添加继承关系
@Component
public class SmallDog {
    @Override
    public String toString() {
        return "SmallDog";
    }
}
<!-- 细粒度过滤 -->
<!-- 默认扫描规则:base-package下所有的类,所有的子包,所有子包下的类都会被扫描 -->
<context:component-scan base-package="com.newcapec">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <context:exclude-filter type="assignable" expression="com.newcapec.bean.Dog"/>
</context:component-scan>

Custom annotation implementations do not include:

public @interface MyFilter {
}
<context:component-scan base-package="com.newcapec">
    <!--所有添加MyFilter注解的都排除在外-->
    <context:exclude-filter type="annotation" expression="com.newcapec.annotation.MyFilter"/>
</context:component-scan>

Contains only:

<context:component-scan base-package="com.newcapec" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

4.3 Configuring Beans

Spring provides the following multiple annotations, which can be directly annotated on Java classes to define them as Spring Beans.

annotation illustrate
@Component This annotation is used to describe the Bean in Spring. It is a generalized concept, which only represents a component (Bean) in the container, and can be used at any level of the application, such as the Service layer, Dao layer, etc. When using it, you only need to mark the annotation on the corresponding class.
@Repository This annotation is used to identify the class of the data access layer (Dao layer) as a bean in Spring, and its function is the same as @Component.
@Service This annotation usually acts on the business layer (Service layer), and is used to identify the class of the business layer as a bean in Spring, and its function is the same as that of @Component.
@Controller This annotation usually acts on the control layer (such as Action of Struts2, Controller of SpringMVC), and is used to identify the class of the control layer as a bean in Spring, and its function is the same as @Component.

Public attribute value: indicates the name of the Bean.

Entity class:

@Component
public class Person {
    private int id;
    private String name;
    private double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

Dao interface and its implementation class:

public interface PersonDao {
    void insertPerson();
}

@Repository("personDao")
public class PersonDaoImpl implements PersonDao {
    @Override
    public void insertPerson() {
        System.out.println("PersonDaoImpl insertPerson()执行了...");
    }
}

Service interface and its implementation class:

public interface PersonService {
    void insertPerson();
}

@Service("personService")
public class PersonServiceImpl implements PersonService {
    @Override
    public void insertPerson() {
        System.out.println("PersonServiceImpl insertPerson()执行了...");
    }
}

Control layer code:

@Controller
public class PersonController {
    public void insertPerson(){
        System.out.println("PersonController insertPerson()执行了...");
    }
}

test:

public class AnnotationTest {

    @Test
    public void testBeanAnnotation(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        try {
            Dog dog = ac.getBean("dog", Dog.class);
            System.out.println(dog);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("------------------------------------");

        try {
            SmallDog smallDog = ac.getBean("smallDog" ,SmallDog.class);
            System.out.println(smallDog);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("------------------------------------");

        try {
            Person p1 = ac.getBean("person", Person.class);
            System.out.println(p1);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("------------------------------------");

        try {
            PersonDao personDao = ac.getBean("personDao", PersonDao.class);
            personDao.insertPerson();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("------------------------------------");

        try {
            PersonService personService = ac.getBean("personService", PersonService.class);
            personService.insertPerson();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        System.out.println("------------------------------------");

        try {
            PersonController personController = ac.getBean("personController", PersonController.class);
            personController.insertPerson();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

4.4 Assembly of components

We can assemble the defined Bean into other Beans through the following annotations.

@Value: Inject literal values ​​for component properties.

public class Person {

    /*
     * 简单类型的依赖注入
     * @Value
     * 作用:依赖注入,注入字面值
     * 位置:成员变量,方法(setter方法)
     * 		我们一般情况下都是写在成员变量上面:
     *		1、成员变量位于类内部的顶部,方便查找 
     *		2、后期使用Lombok插件,没有getter和setter方法
     * 扩展使用:结合Spring表达式加载properties中的数据
     */
    @Value("10001")
    private int id;
    @Value("张三")
    private String name;
    @Value("3000.8")
    private double money;

    //省略
}

@Autowired and @Resource: Automatic assembly annotations, that is, automatic injection.

@Autowired: It can be applied to Bean's attribute variables, setter methods, non-setter methods and constructors, etc., and is assembled according to the type of Bean by default.

  • Constructor methods, common properties (even non-public), and all methods with parameters can be annotated with @Authwired;

  • All properties annotated with @Autowired require that the dependent bean object must exist. An exception is thrown when Spring cannot find a matching bean wiring property. If the attribute allows a null value, you can set the required attribute of the @Authwired annotation to false;

  • When there are multiple bean objects of compatible types in the IOC container, autowiring by type will not work. At this time, you can provide the name of the bean in the @Qualifier annotation, and Spring will automatically assemble it by name;

  • The @Authwired annotation can also be applied to properties of array type, and Spring will automatically assemble all matching beans;

  • The @Authwired annotation can also be applied to collection properties. At this time, Spring reads the type information of the collection, and then automatically assembles all compatible beans;

  • When the @Authwired annotation is used on java.util.Map, if the key value of the Map is String, then Spring will automatically assemble a bean compatible with the value type of the Map, and the name of the bean is used as the key value;

  • In the old version of IDEA, if the interface does not implement the class, the @Authwired annotation will report red, but it will not affect the use. The new version of IDEA does not affect.

@Qualifier: used in conjunction with the @Autowired annotation, the default assembly by Bean type will be modified to be assembled by the instance name of the Bean, and the instance name of the Bean is specified by the parameter of the @Qualifier annotation.

@Service("personService")
public class PersonServiceImpl implements PersonService {

    /*
     * service->dao传统写法:
     *  在service中创建dao对象,然后调用指定的方法
     */
    //private PersonDao personDao = new PersonDaoImpl();

    /*
     * service->dao XML配置写法:
     * <bean id="personDao" class="com.newcapec.dao.impl.PersonDaoImpl"/>
     *  <bean id="personService" class="com.newcapec.service.impl.PersonServiceImpl" p:personDao-ref="personDao"/>
     */
    /*private PersonDao personDao;

    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }*/

    /*
     * service->dao @Autowired注解写法:
     * 实现自定义类型的依赖注入,无需setter方法,自动装配
     *
     * 位置:目前主要使用在成员变量
     * 配置:required默认值为true,表示当前依赖注入的对象必须在IOC容器中存在,否则抛出异常
     *
     * @Autowired注解:
     *  默认按照 Bean 的类型进行装配
     *  如果存在多个该类型bean存在,那么自动切换到按名称匹配
     *  如果存在多个该类型bean存在,并且多个对象的bean名称与名称匹配失败,则抛出异常
     *      解决方法:@Qualifier 指定bean名称
     */
    //@Autowired
    @Autowired(required = false)
    @Qualifier("personDaoImpl")
    private PersonDao personDao;

    @Override
    public void insertPerson() {
        System.out.println("PersonServiceImpl insertPerson()执行了...");

        if (personDao != null) {
            personDao.insertPerson();
        }
    }
}
@Test
public void testAutowired(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

    try {
        PersonService personService = ac.getBean("personService", PersonService.class);
        personService.insertPerson();
    }catch (Exception e){
        System.out.println(e.getMessage());
    }
}

@Resource: The function is the same as Autowired, the difference is that @Autowired is assembled according to the Bean type by default, while @Resource is assembled according to the Bean name by default. There are two important attributes in @Resource: name and type.

  • The @Resource annotation requires a bean name attribute. If the attribute is empty, the variable or method name at the annotation is automatically used as the bean name;

  • Spring resolves the name attribute to the bean's instance name, and the type attribute to the bean's instance type.

  • If the name attribute is specified, assemble by instance name;

  • If the type attribute is specified, it will be assembled according to the Bean type;

  • If none are specified, assemble according to the Bean instance name first, and then assemble according to the Bean type if they cannot match; if they cannot match, NoSuchBeanDefinitionException will be thrown.

@Controller
public class PersonController {

    @Resource
    private PersonService personService;

    public void insertPerson(){
        System.out.println("PersonController insertPerson()执行了...");

        personService.insertPerson();
    }
}

4.5 Java Config

    JavaConfig was incorporated into Spring from an independent project in Spring 3.0. JavaConfig can be regarded as a Spring configuration file for Bean assembly, that is, a Spring container, except that the container is not an XML file, but a Java class written by the programmer using Java himself.

Dept.java:

public class Dept {
    private int deptno;
    private String dname;

    public int getDeptno() {
        return deptno;
    }

    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptno=" + deptno +
                ", dname='" + dname + '\'' +
                '}';
    }
}

Emp.java:

public class Emp {
    private int empno;
    private String ename;
    private Dept dept;

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", dept=" + dept +
                '}';
    }
}

Configuration class:

    Define the JavaConfig class and use the @Configuration annotation on the class to use the current class as a Spring container to complete the creation of the Bean. Using @Bean on the method of this JavaConfig will cause the result returned by a normal method to be a Bean instance with the specified name.

/*
 * 通过@Configuration注解,让该类成为Spring的配置类
 *
 * @Configuration注解
 *  作用:表示当前类为配置类,类似于applicationContext.xml
 */
@Configuration
public class MyConfig {
    /*
     * 配置bean:主要用于第三方jar中的类,自定义类一般使用@Component、@Repository、@Service、@Controller
     * 实现方式:自定义方法+@Bean注解
     * 自定义方法的返回值:Bean的类型
     * 自定义方法的名称:Bean的名称
     *
     * @Bean注解:
     *  name/value属性:配置bean的名称
     *  autowire:自动注入的方式
     */
    @Bean("dept")
    public Dept getDept() {
        Dept dept = new Dept();
        dept.setDeptno(10);
        dept.setDname("研发部");
        return dept;
    }

    //该注解表示:将一个叫做emp的对象放入IOC容器中
    //并且通过byType的方式注入dept
    @Bean(name = "emp", autowire = Autowire.BY_TYPE)
    public Emp getEmp() {
        Emp emp = new Emp();
        emp.setEmpno(8001);
        emp.setEname("张三");
        return emp;
    }
}

test:

public class JavaConfigTest {

    @Test
    public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        Dept dept = ac.getBean("dept", Dept.class);
        System.out.println(dept);

        Emp emp = ac.getBean("emp", Emp.class);
        System.out.println(emp);
    }
}

4.6 Implementation of AOP

4.6.1 Enable AOP annotations

<!-- 开启AOP注解 -->
<aop:aspectj-autoproxy/>

4.6.2 Annotations used in AOP

  • @Aspect: configure the aspect class

  • @Before: configure pre-notification

  • @After: configure post-notification

  • @AfterReturning: configuration return notification

  • @AfterThrowing: configure exception notification

  • @Order: configuration aspect priority

  • @Pointcut: Configure pointcut expressions

@Component
@Aspect
@Order(2)
public class LogAspect {

    @Before("execution(* com.newcapec.service.impl.*.*(..))")
    public void beforeMethod() {
        System.out.println("AOP日志记录:前置通知......");
    }

    //公共切点表达式
    @Pointcut("execution(* com.newcapec.service.impl.*.*(..))")
    public void exp() {
    }

    @After("exp()")
    public void afterMethod() {
        System.out.println("AOP日志记录:后置通知......");
    }

    @AfterReturning(value = "exp()", returning = "result")
    public void afterReturnMethod(Object result) {
        System.out.println("AOP日志记录:返回通知......" + result);
    }

    @AfterThrowing(value = "exp()", throwing = "ex")
    public void afterThrowMethod(Exception ex) {
        System.out.println("AOP日志记录:异常通知......" + ex);
    }
}
@Component
@Aspect
@Order(1)
public class OtherAspect {

    @Before("execution(* com.newcapec.service.impl.*.*(..))")
    public void beforeM(){
        System.out.println("OtherAspect的beforeM方法.....");
    }
}

4.7 Transaction Management

4.7.1 Enable transaction annotations

<!-- 1.配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 注入数据源-->
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 2.开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

4.7.2 Transaction annotations

Annotate @Transactional on the transaction method:

@Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.READ_COMMITTED,
                readOnly = true,timeout = 20,rollbackFor = {ClassNotFoundException.class})
public void transfer(int fromId, int toId, double money) throws Exception {
}

Guess you like

Origin blog.csdn.net/ligonglanyuan/article/details/124787811