preface

So far, I have simply studied the Spring Core module,…. So we’ve turned on the Spring AOP module… Before covering AOP modules, let’s first cover the Cglib proxy and how to implement AOP programming manually

Additional agent

Before explaining Cglib, let’s review static and dynamic proxies…. I’ve blogged about static proxies, dynamic proxies before: blog.csdn.net/hon_3y/arti…

Because static proxies need to implement the same interface of the target object, you can end up with very, very many proxy classes…. Bad maintenance —-> Hence the dynamic proxy

Dynamic proxies also have a constraint: the target object must have an interface, without which dynamic proxies cannot be implemented….. —–> Hence the cglib proxy

The cglib proxy, also known as a subclass proxy, builds a subclass from memory to extend the functionality of the target object!

  • CGLIB is a powerful, high-performance code generation package that extends Java classes and implements Java interfaces at run time. It is widely used by many AOP frameworks, such as Spring AOP and Dynaop, to provide methods for interception.

Write the Cglib proxy

Here’s how to write a Cglib proxy:

  • You need to import the cglib -jar file, but the Spring core package already includes cglib functionality, so you can simply import spring-core-3.2.5.jar.
  • Once feature packs are introduced, subclasses can be built dynamically in memory
  • The class of the agent cannot be final, otherwise an error will be reported.
  • If the methods of the target object are final/static, they are not intercepted, that is, no additional business methods of the target object are executed.
// Implement the MethodInterceptor interface
public class ProxyFactory implements MethodInterceptor{
	
	// Maintain the target object
	private Object target;
	public ProxyFactory(Object target){
		this.target = target;
	}
	
	// Create a proxy object for the target object
	public Object getProxyInstance(a){
		/ / 1. Utility class
		Enhancer en = new Enhancer();
		//2. Set the parent class
		en.setSuperclass(target.getClass());
		// set the callback function
		en.setCallback(this);
		//4. Create subclasses (proxy object)
		return en.create();
	}
	

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		
		System.out.println("Start transaction.....");
		
		// Execute the target object's method
		//Object returnValue = method.invoke(target, args);
		 proxy.invokeSuper(object, args); 
		System.out.println("Submit transaction.....");
		
		returnreturnValue; }}Copy the code
  • Testing:

public class App {

    public static void main(String[] args) {

        UserDao userDao = new UserDao();

        UserDao factory = (UserDao) newProxyFactory(userDao).getProxyInstance(); factory.save(); }}Copy the code

Cglib is used to compensate for dynamic proxies.


Implement AOP programming manually

AOP faceted programming:

  • AOP enables the separation of “business code” from “concern code.

Let’s look at a piece of code:


// Save a user
public void add(User user) { 
		Session session = null; 
		Transaction trans = null; 
		try { 
			session = HibernateSessionFactoryUtils.getSession();   // focus code
			trans = session.beginTransaction();    // focus code
			 
			session.save(user);     // Core business code
			 
			trans.commit();     / /... [Concern code]

		} catch (Exception e) {     
			e.printStackTrace(); 
			if(trans ! =null){ 
				trans.rollback();   / /.. [Concern code]}}finally{ 
			HibernateSessionFactoryUtils.closeSession(session);   / / / /.. [Concern code]}}Copy the code
  • Concern code is code that is executed repeatedly.
  • Separation of business code from concern code, benefits?
    • Focus code is written once;
    • Developers only need to focus on the core business;
    • At runtime, focus code is dynamically embedded when core business code is executed; “Agent”

Case Study:

  • IUser interface

public interface IUser {

    void save(a);
}

Copy the code

Let’s take this step by step. First, our UserDao has a save() method that opens and closes transactions each time


// @component --> You can use this anywhere
@Repository  //--> This is used in the Dao layer
    public class UserDao {

    public void save(a) {

        System.out.println("Start transaction");
        System.out.println("DB: Save user");
        System.out.println("Close transaction"); }}Copy the code
  • When we first learned the basics of Java, we knew that if some function is often needed, we can encapsulate it as a method:

// @component --> You can use this anywhere
@Repository  //--> This is used in the Dao layer
    public class UserDao {

    public void save(a) {

        begin();
        System.out.println("DB: Save user");
        close();
        
    }

    public void begin(a) {
        System.out.println("Start transaction");
    }
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code
  • Now, we might have multiple DAOs, all of which need to have the ability to start and close transactions, but now only the UserDao has these two methods, so the reuse is not high enough. So let’s extract a class

public class AOP {
    
    public void begin(a) {
        System.out.println("Start transaction");
    }
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code
  • When the UserDao maintains this variable, it simply calls the method to use it.

@Repository  //--> This is used in the Dao layer
public class UserDao {


    AOP aop;

    public void save(a) {

        aop.begin();
        System.out.println("DB: Save user"); aop.close(); }}Copy the code
  • At present, I still need to manually open and close the transaction in the userDao. Still not elegant enough. What I want: to dynamically open and close a transaction when I call the userDao’s save() method. So, we use agents. Of course, it’s userDao that actually implements the methods and AOP that does the work, so their references need to be maintained in the proxy.
public class ProxyFactory {
    // Maintain the target object
    private static Object target;

    // Maintain key code classes
    private static AOP aop;
    public static Object getProxyInstance(Object target_, AOP aop_) {

        // The target object and the keypoint code classes are passed in from the outside
        target = target_;
        aop = aop_;

        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        aop.begin();
                        Object returnValue = method.invoke(target, args);
                        aop.close();

                        returnreturnValue; }}); }}Copy the code

Factory static method:

  • Add AOP to the IOC container



// Add the object to the container
@Component
public class AOP {

    public void begin(a) {
        System.out.println("Start transaction");
    }
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code
  • Put the UserDao into the container

@Component
public class UserDao {

    public void save(a) {

        System.out.println("DB: Save user"); }}Copy the code
  • Turn on annotation scanning in the configuration file to create proxy objects using the factory static method

<?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:p="http://www.springframework.org/schema/p"
       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">


    <bean id="proxy" class="aa.ProxyFactory" factory-method="getProxyInstance">
        <constructor-arg index="0" ref="userDao"/>
        <constructor-arg index="1" ref="AOP"/>
    </bean>

    <context:component-scan base-package="aa"/>





</beans>
Copy the code
  • Test, get the UserDao object, call the method


public class App {

    public static void main(String[] args) {

        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");


        IUser iUser = (IUser) ac.getBean("proxy"); iUser.save(); }}Copy the code

Factory non-static methods

The factory static method used above creates the proxy class object. We also use the non-static factory method to create objects.


package aa;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/** * Created by ozc on 2017/5/11. */

public class ProxyFactory {

    public Object getProxyInstance(final Object target_, final AOP aop_) {

        // The target object and the keypoint code classes are passed in from the outside

        return Proxy.newProxyInstance(
                target_.getClass().getClassLoader(),
                target_.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        aop_.begin();
                        Object returnValue = method.invoke(target_, args);
                        aop_.close();

                        returnreturnValue; }}); }}Copy the code

Configuration files: Create factories first and then proxy objects

<?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:p="http://www.springframework.org/schema/p"
       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">



    <! Create a factory -->
    <bean id="factory" class="aa.ProxyFactory"/>


    <! Create proxy from factory -->
    <bean id="IUser" class="aa.IUser" factory-bean="factory" factory-method="getProxyInstance">
        <constructor-arg index="0" ref="userDao"/>
        <constructor-arg index="1" ref="AOP"/>
    </bean>


    <context:component-scan base-package="aa"/>


</beans>
Copy the code


Overview of AOP

Aop: Aspect Object programming

  • Function: Separate focus code from business code!
  • Faceted programming is the extraction of repetitive code for many functions and the dynamic insertion of “faceted code” into business methods at run time.

Focus:

  • Repeating code is called a concern.

// Save a user
public void add(User user) { 
		Session session = null; 
		Transaction trans = null; 
		try { 
			session = HibernateSessionFactoryUtils.getSession();   // focus code
			trans = session.beginTransaction();    // focus code
			 
			session.save(user);     // Core business code
			 
			trans.commit();     / /... [Concern code]

		} catch (Exception e) {     
			e.printStackTrace(); 
			if(trans ! =null){ 
				trans.rollback();   / /.. [Concern code]}}finally{ 
			HibernateSessionFactoryUtils.closeSession(session);   / / / /.. [Concern code]}}Copy the code

Section:

  • Classes formed by concerns are called facets!

public class AOP {

    public void begin(a) {
        System.out.println("Start transaction");
    }
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code

Starting point:

  • Implement the target object method to dynamically populate the aspect code.
  • Pointcut expressions specify which methods of which classes to intercept; Implants the specified class with the aspect class code at runtime.

Pointcut expressions:

  • Specifies which methods of which classes are intercepted

Use Spring AOP to develop steps

1) First introduce aop related JAR files (AspectJ AOP excellent components)

  • Spring aOP-3.2.5.release.jar
  • Aopalliance.jar 【spring2.5 下 载 /lib/aopalliance】
  • Aspectjweaver. Jar [spring2.5 source /lib/aspectj]
  • Aspectjr.jar [spring2.5 source /lib/aspectj] / aspectj-1.8.2\lib]

Note: using spring2.5 jar files may cause problems if using jdk1.7.

  • You need to upgrade the AspectJ component to use the JAR files provided in AspectJ-1.8.2.

2) Aop namespaces are introduced in bean.xml

  • xmlns:context="http://www.springframework.org/schema/context"
  • http://www.springframework.org/schema/context
  • http://www.springframework.org/schema/context/spring-context.xsd

The introduction of the jar package

Introduce four JAR packages:

Importing namespaces


<?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:p="http://www.springframework.org/schema/p"
       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">
    
</beans>
Copy the code

Annotation approach to AOP programming

We used to implement AOP programming manually by writing our own proxy factories. Now with Spring, we don’t need to write our own proxy factories. Spring will help us create the agent factory internally **.

  • In other words, we don’t have to write proxy objects ourselves.

Therefore, all we need to worry about is the aspect class, the pointcut, and writing the cut expression to specify what method to intercept!

Using the above example as an example, AOP programming is implemented using Spring’s annotations

Turn on the AOP annotation approach in the 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:p="http://www.springframework.org/schema/p"
       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">


    <context:component-scan base-package="aa"/>

    <! Enable AOP annotation mode -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
Copy the code

Code:

  • Cut class

@Component
@Aspect// Specify the section class
public class AOP {


	// The values inside are pointcut expressions
    @Before("execution(* aa.*.*(..) )")
    public void begin(a) {
        System.out.println("Start transaction");
    }


    @After("execution(* aa.*.*(..) )")
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code
  • The UserDao implements the IUser interface

@Component
public class UserDao implements IUser {

    @Override
    public void save(a) {
        System.out.println("DB: Save user"); }}Copy the code
  • IUser interface

public interface IUser {
    void save(a);
}

Copy the code
  • Test code:

public class App {

    public static void main(String[] args) {

        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");

		// Here is the proxy object....
        IUser iUser = (IUser) ac.getBean("userDao"); System.out.println(iUser.getClass()); iUser.save(); }}Copy the code


The target object has no interface

Above we test that the UserDao has the IUser interface and uses the dynamic proxy internally… So this time we are testing that the target object has no interface

  • OrderDao does not implement an interface

@Component
public class OrderDao {

    public void save(a) {

        System.out.println("I've got it in!!"); }}Copy the code
  • Test code:


public class App {

    public static void main(String[] args) {

        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");

        OrderDao orderDao = (OrderDao) ac.getBean("orderDao"); System.out.println(orderDao.getClass()); orderDao.save(); }}Copy the code


Optimization and AOP annotation APIS

API:

  • @aspect specifies a class as the Aspect class

  • @Pointcut(“execution( cn.itcast.e_aop_anno.. (..) )”) specifies the pointcut expression *

  • @before (“pointCut_()”) pre-notification: the target method is executed Before

  • @after (“pointCut_()”) postnotification: execute After target method (always execute)

  • Notification after return of @afterRETURNING (“pointCut_()”)

  • @afterthrowing (“pointCut_()”) Exception notification: Executed when an exception occurs

  • @around (“pointCut_()”) surround notification: execute Around the target method

  • Testing:

	
	// Pre-notification: execute before executing the target method
	@Before("pointCut_()")
	public void begin(a){
		System.out.println("Start transaction/exception");
	}
	
	// Post/final notification: executes after executing the target method [executes eventually regardless of exceptions]
	@After("pointCut_()")
	public void after(a){
		System.out.println("Commit transaction/Close");
	}
	
	// Notification after return: execute after calling target method
	@AfterReturning("pointCut_()")
	public void afterReturning(a) {
		System.out.println("afterReturning()");
	}
	
	Exception notification: This concern code is executed when the target method executes an exception
	@AfterThrowing("pointCut_()")
	public void afterThrowing(a){
		System.out.println("afterThrowing()");
	}
	
	// Surround notification: execute around the target
	@Around("pointCut_()")
	public void around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("Surround front....");
		pjp.proceed();  // Execute the target method
		System.out.println("Surround back....");
	}

Copy the code

To optimize the

Our code looks like this: every time we write Before, After, etc., we have to rewrite the pointcut expression, which is not elegant.


    @Before("execution(* aa.*.*(..) )")
    public void begin(a) {
        System.out.println("Start transaction");
    }


    @After("execution(* aa.*.*(..) )")
    public void close(a) {
        System.out.println("Close transaction");
    }

Copy the code

As a result, we use the @pointcut annotation to specify Pointcut expressions and reference them wherever they are used.

  • Our code can then be modified to look like this:

@Component
@Aspect// Specify the section class
public class AOP {


    // Specify the pointcut expression that intercepts which methods of which class
    @Pointcut("execution(* aa.*.*(..) )")
    public void pt(a) {}@Before("pt()")
    public void begin(a) {
        System.out.println("Start transaction");
    }


    @After("pt()")
    public void close(a) {
        System.out.println("Close transaction"); }}Copy the code

XML method to implement AOP programming

First, let’s remove all the notes…

  • XML file 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:p="http://www.springframework.org/schema/p"
       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">


    <! -- Object instance -->
    <bean id="userDao" class="aa.UserDao"/>
    <bean id="orderDao" class="aa.OrderDao"/>

    <! -- Section class -->
    <bean id="aop" class="aa.AOP"/>

    <! - AOP configuration - >
    <aop:config >

        <! Define which methods to intercept in the expression
        <aop:pointcut id="pointCut" expression="execution(* aa.*.*(..) )"/>

        <! -- Specify which class is the section class -->
        <aop:aspect ref="aop">

            <! Specify which methods of the section class to execute when intercepting.
            <aop:before method="begin" pointcut-ref="pointCut"/>
            <aop:after method="close" pointcut-ref="pointCut"/>

        </aop:aspect>
    </aop:config>

    
</beans>

Copy the code
  • Testing:

public class App {

    @Test
    public  void test1(a) {

        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");

        OrderDao orderDao = (OrderDao) ac.getBean("orderDao");

        System.out.println(orderDao.getClass());

        orderDao.save();

    }

    @Test
    public  void test2(a) {

        ApplicationContext ac =
                new ClassPathXmlApplicationContext("aa/applicationContext.xml");

        IUser userDao = (IUser) ac.getBean("userDao"); System.out.println(userDao.getClass()); userDao.save(); }}Copy the code

Test OrderDao

Test UserDao


Pointcut expression

Pointcut expressions are basically used to configure which methods of which classes to intercept

Check official documents

. Let’s look for the syntax in the documentation…

Search within the document :execution(

Syntax parsing

So its syntax looks like this:


execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

Copy the code

Symbol explanation:

  • ? The sign stands for 0 or 1, so you don’t have to write it
  • The * symbol represents any type, 0 or more
  • The method parameters are.. Represents a variable parameter

Parameter explanation:

  • modifiers-pattern? 【 modify type, can not write 】
  • Ret-type-pattern [method return value type, required]
  • declaring-type-pattern? Method declaration type, can not write
  • Name-pattern (param-pattern)
  • throws-pattern? The exception type thrown by the method can be omitted.

There are also some official examples for us to understand:

The test code


		<! Public method -->
		<! --<aop:pointcut expression="execution(public * *(..) )" id="pt"/>-->
		
		<! -- [save method] -->
		<! --<aop:pointcut expression="execution(* save*(..) )" id="pt"/>-->
		
		<! --> < span style = "max-width: 100%; clear: both;
		<! --<aop:pointcut expression="execution(public * cn.itcast.g_pointcut.OrderDao.save(..) )" id="pt"/>-->
		
		<! Intercept all methods of a specified class -->
		<! --<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.*(..) )" id="pt"/>-->
		
		<! -- intercepting the specified package and all methods of its classes -->
		<! --<aop:pointcut expression="execution(* cn.. *. * (..) )" id="pt"/>-->
		
		<! -- [multiple expressions] -->
		<! --<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) || execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<! --<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) or execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<! --> < span style = "box-sizing: border-box! Important;
		<! --<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) &amp; &amp; execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		<! --<aop:pointcut expression="execution(* cn.itcast.g_pointcut.UserDao.save()) and execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
		
		<! -->
		<! --<aop:pointcut expression="! execution(* cn.itcast.g_pointcut.OrderDao.save())" id="pt"/>-->
Copy the code

If the article has the wrong place welcome to correct, everybody exchanges with each other. Students who are used to reading technical articles on wechat and want to get more Java resources can follow the wechat public account :Java3y