Spring core technologies IOC and AOP

Keywords: Java Spring

preface

Spring core:
IOC: inversion of control, leaving the process of creating objects to the Spring container for management, reducing the direct coupling of objects
AOP: aspect oriented and enhanced without modifying the source code, such as permission check, transaction, log collection, etc

IOC

Spring bottom layer is actually based on xml parsing and reflection mechanism, and the bottom layer implements IOC process through object factory
The pseudo code is as follows:

/**
 * @Description
 * @Author Fangchenjiang
 * @Date 2021/10/13 11:56
 */
public class MyFactory {

    public static Object  getObject(){
        //1. Parse xml configuration file to get classValue
        String classValue=classValue;  //xml parsing
        //2. Get Class by reflection
        Class<?> cls = Class.forName(classValue);
        //3. Instantiate object
        Object instance = cls.newInstance();
        return instance;
    }
}

Manually calling IOC procedure based on xml

		
        //1. Load configuration file
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        //2. Get object instance
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
		
		//bean.xml
		<?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">
		    <!--adopt Spring create object-->
		    <bean id="user" class="com.gz.xf.domain.User">
	
	    	</bean>
		</beans>

However, in the Spring underlying IOC, the process is very complex. The underlying implementation is mainly through the BeanFactory and ApplicationContext interfaces; BeanFactory is the basic implementation of IOC. It is used inside Spring to initialize Spring related components. Direct external calls are not recommended. ApplicationContext is a sub interface of BeanFactory, which is more powerful and can be used directly

Bean Management (XML based)

In the Spring container, Bean management mainly consists of two steps: object creation and attribute injection (DI). For example, object injection is based on xml. If the construction method is not specified, Spring creates the object by default with the nonparametric construction of the class

		<?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">
		       <!--Construct and inject attributes with no parameters-->
	    <bean id="user" class="com.gz.xf.domain.User">
	            <property name="age" value="20"/>
	            <property name="name" value="xf"/>
	    </bean>

    		<!--Injection through parametric structure-->
	    <bean id="user" class="com.gz.xf.domain.User">
	        <constructor-arg name="age" value="11"/>
	        <constructor-arg name="name" value="xf"/>
	    </bean>
	</beans>

In Spring, there are two types of beans: ordinary Bean and FactoryBean. Ordinary Bean is the class or interface that we need to give to Spring to manage. FactoryBean is a built-in interface in Spring, which is usually implemented by ordinary objects. This interface is used as a factory to return a new object instead of directly returning the Bean instance of the ordinary object. Source code explanation:

* Interface to be implemented by objects used within a {@link BeanFactory} which
* are themselves factories for individual objects. If a bean implements this
* interface, it is used as a factory for an object to expose, not directly as a
* bean instance that will be exposed itself.
/**
 * @Description
 * @Author Fangchenjiang
 * @Date 2021/10/13 14:20
 */
public class Pet  implements FactoryBean<User> {


    //Return the concrete Bean. At this time, the Pet class can be regarded as a factory
    //Returns the Bean of the User class
    @Override
    public User getObject() throws Exception {
        System.out.println("Pet Factory return Bean");
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

Gets the object created by the FactoryBean

	<?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="pet" class="com.gz.xf.domain.Pet"></bean>
	</beans>
//       1. Load configuration file
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//        2. Get object instance
        User user = applicationContext.getBean("pet",User.class);
        System.out.println(user);

Bean lifecycle

The life cycle of a Bean can include the following processes:
1. Load the configuration file and call the parameterless construction object
2. Attribute injection
3. Related processing before initialization (optional, BeanPostProcessor processor needs to be implemented)
4. Perform initialization
5. Post initialization related processing (optional, BeanPostProcessor processor needs to be implemented)
6. The container is closed and the Bean is destroyed

  • Person object
	/**
 * @Description
 * @Author Fangchenjiang
 * @Date 2021/10/13 16:01
 */
public class PerSon {

    private String name;
    public PerSon() {
        System.out.println("1.create object");
    }


    public void initBean(){
        System.out.println("4.initialization Bean");
    }

    public void destory(){
        System.out.println("6.Close the container,Destroy instance");
    }

    public void setName(String name) {
        System.out.println("2.Attribute injection:"+name);
        this.name = name;
    }
}
  • Optional, implement the BeanPostProcessor processor
/**
 * @Description
 * @Author Fangchenjiang
 * @Date 2021/10/13 16:04
 */
public class PersonProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("3.Pre initialization processing:"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5.Post initialization processing:"+beanName);
        return bean;
    }
}
  • Configuration file bean.xml
<?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">

    <!--To instantiate Bean-->
    <bean id="person" class="com.gz.xf.domain.PerSon" init-method="initBean" destroy-method="destory">
        <property name="name" value="Xiao Fang"></property>
    </bean>

    <!--Post Processors -->
    <bean id="personProcessor" class="com.gz.xf.domain.PersonProcessor">

    </bean>
</beans>
  • Life cycle testing
    public void testLifeCycle(){
        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean.xml");
        //Get instance
        PerSon person = applicationContext.getBean("person",PerSon.class);
//        System.out.println(person.toString());
        //Close the container and destroy the Bean
        applicationContext.close();
    }

Bean Management (based on annotation injection)

Modify the configuration file and start component scanning

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--Turn on component scanning-->
    <context:component-scan base-package="com.gz.xf.domain"/>
</beans>

Use @ Component, @ Service and @ Repository annotations to create objects. The specific meaning of the annotation will not be explained

@Component  //Deliver the StudentService object to IOC container management
public class StudentService {

    @Autowired //Properties are injected by type
    private StudentDao studentDao;
    public void doQuery(){
        studentDao.doQuery();
    }
}
@Repository
public class StudentDao {

    public void doQuery(){
        System.out.println("query student");
    }
}

The Dao object is injected through Autowird to call the Dao object in the Service class. Of course, the injected object also needs to be handed over to the IOC container for management. Therefore, the StudentDao class is also modified by * * @ Repository * *

 public void testAnnotation(){

        ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("bean3.xml");
        StudentService studentService = applicationContext.getBean("studentService", StudentService.class);
        studentService.doQuery();
    }

In this way, Dao objects and Service objects are coupled and managed by the Spring container. However, there is a problem that annotation development has not been fully achieved. How to realize full annotation development without xml Configuration? We can replace the xml file with * * @ Configuration * * provided by Spring, * * Component? Is this a little linked to SpringBoot?

/**
 * @Description
 * @Author Fangchenjiang
 * @Date 2021/10/13 18:42
 */
@Configuration  //Configuration class, replacing xml configuration
@ComponentScan(basePackages = "com.gz.xf.domain")  //The specified component scan is equivalent to < context: component scan base package = "com. GZ. XF. Domain" / >
public class Myconfig {


}

Call Bean instance method through configuration class

		//Configuration based classes
        ApplicationContext applicationContext= new AnnotationConfigApplicationContext(Myconfig.class);
        StudentService studentService = applicationContext.getBean("studentService",StudentService.class);
        //Bean call
        studentService.doQuery();

AOP

For aspect oriented programming, the underlying essence is to enhance functions through dynamic agents. Please click dynamically JDK dynamic agent However, AOP is not proposed by Spring, but other independent frameworks. Therefore, to implement AOP in the original Spring project, you need to add the following dependencies:

		<!--AOP-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

There are several important concepts in AOP. Here I summarize them in popular language
section
A class that implements basic function enhancement actions (marked by @ Aspect annotation), which mainly includes pointcuts, notifications, enhancement logic, etc
breakthrough point
Some methods that actually need to be enhanced in business classes
notice
Some operations at the specified pointcut (the target method to be enhanced) are a bit similar to the idea of interceptor, which can be understood by comparison
@Before
Pre notification: the target enhancement method is notified before execution
@After
Final notification, notification after completion of target enhancement method implementation
AfterReturning
The notification is returned. The target enhancement method executes normally. The notification is returned
Around
Surround notification, pre execution notification of target enhancement method and post final execution notification of target method
AfterThrowing
Exception notification: the target enhancement method executes. If an exception occurs, it will be notified

Now let's play games with boys to enhance the AOP function of playing games

  • xml configuration file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd"
        >

    <!--Turn on component scanning-->
    <context:component-scan base-package="com.gz.xf.domain.aopannotation"/>

    <!--open aop agent-->
    <aop:aspectj-autoproxy/>


</beans>
  • Business class
 	//Target business class
 	@Component
	public class BoyService {

    public void palyGame(){
        System.out.println("Fighting the peace elite");
    }
}
  • The aspect of business classes, where execution specifies which class methods are AOP enhanced
@Component
@Aspect
public class BoyAspect {

    //breakthrough point
    @Pointcut("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))")
    public void point(){


    }
//    @Before("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))")
    @Before("point()")
    public void before(){

        System.out.println("The boy is ready to play games");
    }

//    @After("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))")
    @After("point()")
    public void  after(){
        System.out.println("The boy finished the game");
    }

//    @AfterReturning(("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))"))
    @AfterReturning("point()")
    public void  AfterReturning(){
        System.out.println("After the boy plays the game, the method returns");
    }

//    @Around((("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))")))
    @Around("point()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("Before surround");
        joinPoint.proceed();
        System.out.println("After surround");
    }

//    @AfterThrowing((("execution(* com.gz.xf.domain.aopannotation.BoyService.*(..))")))
    @AfterThrowing("point()")
    public void afterThrowing(){
        System.out.println("Exception notification");
    }
}
  • Get the Bean and call the target method
  		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop.xml");
        BoyService boyService = applicationContext.getBean("boyService", BoyService.class);
        boyService.palyGame();


The above is to implement AOP based on xml. If you switch to annotation mode, you only need to write a configuration class:

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.gz.xf.domain.aopannotation")
public class AopConfig {
}

affair

Spring also has good support for transactions. It mainly understands declarative transactions, and its implementation methods include xml configuration and annotation (key points)

  • xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
	   http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
        ">

    <!--Turn on component scanning-->
    <context:component-scan base-package="com.gz.xf.domain.tx"/>

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--jdbcTemplate-->
    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--Transaction manager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource"/>

    </bean>
    
    <!--Configure implementation transactions-->
    <tx:advice id="txAdvice">
        <tx:attributes>
            <tx:method name="change*"/>
        </tx:attributes>
    </tx:advice>

    <!--affair aop to configure-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.gz.xf.domain.tx.AccountService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
    </aop:config>
</beans>
  • Annotation configuration, just mark * * @ Transactional * * annotation on the class or method that needs to implement transaction
@Configuration
@ComponentScan("com.gz.xf.domain.tx")
@EnableTransactionManagement
public class TxConfig {

    //data source
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/xf_test?characterEncoding=utf-8&useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    //JdbcTemplate
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //DataSourceTransactionManager
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

Transactional annotation
This annotation contains the core concepts related to transactions

	//Propagation behavior of transactions
	Propagation propagation() default Propagation.REQUIRED;
	//Isolation level of transaction
	Isolation isolation() default Isolation.DEFAULT;
	//Transaction timeout
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
	//Read only
	boolean readOnly() default false;

Address of knowledge point code warehouse: https://gitee.com/iamFangcJ/spring_demo

Posted by d1223m on Thu, 14 Oct 2021 19:34:48 -0700