spring learning (3) spring AOP

For more spring-related articles, see
Spring Learning (1)
Spring Learning (2) Ambiguity of Autowiring

Fourth, spring AOP
Spring AOP (Aspect Oriented Programming) is aspect-oriented programming. In our usual oop (Object Oriented Programming, object-oriented programming), there will inevitably be some places that cannot be taken care of. For example, our log Function. In most business logic, logging is essential. Based on oop, we need to add code to enable logging when implementing the core functions of each object. These codes are not related to the business logic we need to implement, and will be reused in many places. Therefore, we hope to extract and encapsulate these logics that are not related to the business but are commonly called by multiple modules, so that in the system The amount of repetitive code will be greatly reduced, and the logic of the function will be clearer and easier to maintain.

1. Common terms

  1. Advice: notification, the work to be done by the aspect. There are five types of notifications in the spring aspect: Before, After, Around, After-returning, and After-throwing.
  2. Join point: The connection point, the point of application notification, is a point that can insert the aspect, spring only supports the connection point of the method level
  3. Poincut: Cut point, which defines where the cut face is inserted. Intuitively speaking, it is generally reflected as a cut point expression
  4. Aspect: Aspect, a combination of advice and pointcut, generally a class
  5. Introduction: introduced, allowing us to add new methods or properties to an existing class
  6. Weaving: Weaving, the process of applying an aspect to a target object and creating a new object proxy.

2. Use annotations to create simple aspects
Enable AspectJ automatic proxying in xml files

<!--启用AspectJ自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>

Note proxy-target-class="true"that when this trueproperty is, it is a class-based proxy, using cglib, and when falseit is, it is an interface-based jdk dynamic proxy, and the default value is that false
we can see it through a simple class.

package com.shiqy.controller;

import com.shiqy.config.MyAspectConfig;
import com.shiqy.dao.UserDao;
import com.shiqy.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@Component
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-mybatis.xml")
//@ContextConfiguration(classes = MyAspectConfig.class)
public class MyLogAspectTest {
    @Autowired
    private UserService userService;

    @Autowired
    private UserDao userDao;
    @Test
    public void test() {
        System.out.println(userDao.getClass());
        System.out.println(userService.getClass());
    }
}

At that timeproxy-target-class="false" , the result was

class com.sun.proxy.$Proxy25
class com.sun.proxy.$Proxy27

trueWhen is, the result is

class com.sun.proxy.$Proxy25
class com.shiqy.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$cc3824e3

a simple slice

package com.shiqy.service.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyLogAspect {
    @Before("execution(* com.shiqy.service.impl.UserServiceImpl.*(..))")
    public void beforeMethod(){
        System.out.println("记录日志!!!");
    }

    @After("execution(* com.shiqy.service.impl.UserServiceImpl.*(..))")
    public void afterMethod(){
        System.out.println("记录成功!!!");
    }
}

@AspectJThe annotation indicates that the class is an aspect, @Beforeand the annotation indicates that @Afterthe type of notification is pre-advice and post-advice, which execution()is used to match the execution method that is the connection point, and execution(* com.shiqy.service.impl.UserServiceImpl.*(..))represents UserServiceImplall methods of the class. The role of this aspect is when the specified implementation class is executed. Notifications will be sent before and after any method of .
In the above code, @Beforeand @Afterthe annotated pointcut expressions are redundant, we can use @PointCutannotations to define reusable pointcuts

package com.shiqy.service.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyLogAspect {
    @Pointcut("execution(* com.shiqy.service.impl.UserServiceImpl.*(..))")
    public void myMethod(){ }

    @Before("myMethod()")
    public void beforeMethod(){
        System.out.println("记录日志!!!");
    }

    @After("myMethod()")
    public void afterMethod(){
        System.out.println("记录成功!!!");
    }
}

Next write the test class

package com.shiqy.controller;

import com.shiqy.config.MyAspectConfig;
import com.shiqy.dao.UserDao;
import com.shiqy.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@Component
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-mybatis.xml")
//@ContextConfiguration(classes = MyAspectConfig.class)
public class MyLogAspectTest {
    @Autowired
    private UserService userService;
    @Test
    public void test(){
        long id =1;
        System.out.println(userService.selectUser(id).getUsername());
    }
}

In spring-mybatis.xml, we need to configure
<context:component-scan base-package="com.shiqy.service"/>automatic scanning to get our slices, and the result of the operation is

20:52:26.701 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-commons.properties' could not be found. Skipping.
20:52:26.702 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-log.properties' could not be found. Skipping.
20:52:26.702 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier 'hocon:/reference,/application,/c3p0,/' could not be found. Skipping.
20:52:26.702 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/c3p0.properties' could not be found. Skipping.
20:52:26.801 [main] INFO com.mchange.v2.c3p0.C3P0Registry - Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
20:52:26.850 [main] DEBUG com.mchange.v2.c3p0.management.DynamicPooledDataSourceManagerMBean - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=z8kflt9u1r0kgrq1ycbj82|7fd50002,name=z8kflt9u1r0kgrq1ycbj82|7fd50002 registered.
20:52:26.874 [main] DEBUG com.mchange.v2.c3p0.management.DynamicPooledDataSourceManagerMBean - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=z8kflt9u1r0kgrq1ycbj82|7fd50002,name=z8kflt9u1r0kgrq1ycbj82|7fd50002 unregistered, in order to be reregistered after update.
20:52:26.874 [main] DEBUG com.mchange.v2.c3p0.management.DynamicPooledDataSourceManagerMBean - MBean: com.mchange.v2.c3p0:type=PooledDataSource,identityToken=z8kflt9u1r0kgrq1ycbj82|7fd50002,name=z8kflt9u1r0kgrq1ycbj82|7fd50002 registered.
记录日志!!!
20:52:27.380 [main] INFO com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource - Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 2, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> z8kflt9u1r0kgrq1ycbj82|7fd50002, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> z8kflt9u1r0kgrq1ycbj82|7fd50002, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/springmvc?useUnicode=true&characterEncoding=utf8&useSSL=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 30, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
20:52:27.392 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-commons.properties' could not be found. Skipping.
20:52:27.392 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/mchange-log.properties' could not be found. Skipping.
20:52:27.392 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier '/c3p0.properties' could not be found. Skipping.
20:52:27.392 [main] DEBUG com.mchange.v2.cfg.MConfig - The configuration file for resource identifier 'hocon:/reference,/application,/c3p0,/' could not be found. Skipping.
20:52:27.393 [main] WARN com.mchange.v2.resourcepool.BasicResourcePool - Bad pool size config, start 3 < min 10. Using 10 as start.
20:52:27.394 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - com.mchange.v2.resourcepool.BasicResourcePool@2b0f373b config: [start -> 10; min -> 10; max -> 30; inc -> 3; num_acq_attempts -> 2; acq_attempt_delay -> 1000; check_idle_resources_delay -> 0; max_resource_age -> 0; max_idle_time -> 0; excess_max_idle_time -> 0; destroy_unreturned_resc_time -> 0; expiration_enforcement_delay -> 0; break_on_acquisition_failure -> false; debug_store_checkout_exceptions -> false; force_synchronous_checkins -> false]
20:52:27.394 [main] DEBUG com.mchange.v2.c3p0.impl.C3P0PooledConnectionPoolManager - Created new pool for auth, username (masked): 'ro******'.
20:52:27.394 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - acquire test -- pool size: 0; target_pool_size: 10; desired target? 1
20:52:27.394 [main] DEBUG com.mchange.v2.resourcepool.BasicResourcePool - awaitAvailable(): [unknown]
记录成功!!!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324610590&siteId=291194637