Home >Java >javaTutorial >Detailed explanation of SpringAop in Java

Detailed explanation of SpringAop in Java

黄舟
黄舟Original
2017-10-08 09:34:091460browse

I have been studying SpringAop in the past few days and found some information on the Internet. This link is the original link http://www.cnblogs.com/xrq730/p/4919025.html

AOP

AOP (Aspect Oriented Programming), that is, aspect-oriented programming, can be said to be the supplement and improvement of OOP (Object Oriented Programming, object-oriented programming). OOP introduces concepts such as encapsulation, inheritance, and polymorphism to establish an object hierarchy that is used to simulate a collection of public behaviors. However, OOP allows developers to define vertical relationships, but it is not suitable for defining horizontal relationships, such as logging functions. Logging code is often spread horizontally across all object hierarchies and has nothing to do with the core functionality of the object it corresponds to. This is also true for other types of code, such as security, exception handling, and transparent persistence. Irrelevant code everywhere is called cross cutting. In OOP design, it leads to the duplication of a large amount of code and is not conducive to the reuse of various modules.

AOP technology is just the opposite. It uses a technology called "cross-cutting" to dissect the inside of the encapsulated object and encapsulate the public behaviors that affect multiple classes into a reusable module. And name it "Aspect", which is the aspect. The so-called "aspects" are simply encapsulated logic or responsibilities that have nothing to do with the business but are jointly called by the business modules, so as to reduce the duplication of code in the system, reduce the coupling between modules, and facilitate future operability. and maintainability.

Using "cross-cutting" technology, AOP divides the software system into two parts: Core concerns and Cross-cutting concerns. The main process of business processing is the core concern, and the part that has little relationship with it is the cross-cutting concern. One characteristic of cross-cutting concerns is that they often occur in multiple places in the core concern, and the places are basically similar, such as authority authentication, logs, and things. The role of AOP is to separate various concerns in the system, separating core concerns and cross-cutting concerns.

AOP core concepts

1. Cross-cutting concerns

Which methods should be intercepted and how to deal with them after interception? These concerns are called cross-cutting concerns

2. Aspect

The class is an abstraction of the characteristics of the object, and the aspect is the abstraction of the cross-cutting concerns

3. Joinpoint (joinpoint)

The intercepted point, because Spring only supports method type connection points, so the connection point in Spring refers to the intercepted method. In fact, the connection point is still It can be a field or a constructor

4. Pointcut

Definition of intercepting connection points

5. Advice

The so-called notification refers to the code to be executed after intercepting the connection point. The notifications are divided into five categories: pre-, post-, exception, final, and surrounding notifications

6. Target object

Agent The target object

7. Weave

The process of applying aspects to the target object and causing the creation of the proxy object

8.Introduction

Without modifying the code, the introduction can dynamically add some methods or fields to the class during runtime

Spring’s support for AOP Support

The AOP proxy in Spring is generated and managed by Spring's IOC container, and its dependencies are also managed by the IOC container. Therefore, the AOP proxy can directly use other bean instances in the container as targets, and this relationship can be provided by the dependency injection of the IOC container. Spring's rules for creating a proxy are:

1, By default, Java dynamic proxy is used to create an AOP proxy, so that a proxy can be created for any interface instance

2,When the class that requires a proxy is not a proxy interface, Spring will switch to using CGLIB proxy, or you can force the use of CGLIB

AOP programming is actually a very simple matter. Looking at AOP programming, programs Members only need to participate in three parts:

1. Define common business components

2. Define entry points. One entry point may cross multiple business components

3. Define enhanced processing, which is a processing action woven into the AOP framework for ordinary business components

So the key to AOP programming is to define the entry point and define enhanced processing. Once the appropriate entry point and enhanced processing are defined , the AOP framework will automatically generate an AOP proxy, that is: method of proxy object = enhanced processing + method of proxy object .

The following is a Spring AOP. Simple implementation

Note that before explaining, let me explain one thing: to use Spring AOP, to successfully run the code, it is not enough to only use the jar package provided by Spring to developers. Please go online and download two additional Jar packages:

1, aopalliance.jar

2, aspectjweaver.jar

Let’s start with the XML implementation using Spring AOP. First define an interface:

<?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: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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
            
</beans>

Define two interface implementation classes:

1 public interface HelloWorld
2 {
3     void printHelloWorld();
4     void doPrint();
5 }
public class HelloWorldImpl1 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return ;
    }
}

Cross-cutting concerns, here is the printing time:

public class HelloWorldImpl2 implements HelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }
    
    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return ;
    }
}

With these three classes, You can implement a simple Spring AOP. Take a look at the configuration of aop.xml

public class TimeHandler
{
    public void printTime()
    {
        System.out.println("CurrentTime = " + System.currentTimeMillis());
    }
}

Write a main function to call:

<?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: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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>
</beans>

The running result is:


CurrentTime = 1446129611993Enter HelloWorldImpl1.printHelloWorld()
CurrentTime = 1446129611993CurrentTime = 1446129611994Enter HelloWorldImpl1.doPrint()
CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.printHelloWorld()
CurrentTime = 1446129611994CurrentTime = 1446129611994Enter HelloWorldImpl2.doPrint()
CurrentTime = 1446129611994

看到给HelloWorld接口的两个实现类的所有方法都加上了代理,代理内容就是打印时间

基于Spring的AOP使用其他细节

1、增加一个横切关注点,打印日志,Java类为:

public class LogHandler
{
    public void LogBefore()
    {
        System.out.println("Log before method");
    }
    
    public void LogAfter()
    {
        System.out.println("Log after method");
    }
}

aop.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"
    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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>

测试类不变,打印结果为:

CurrentTime = 1446130273734
Log before method
Enter HelloWorldImpl1.printHelloWorld()
Log after method
CurrentTime = 1446130273735

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl1.doPrint()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273736
Log before method
Enter HelloWorldImpl2.printHelloWorld()
Log after method
CurrentTime = 1446130273736

CurrentTime = 1446130273737
Log before method
Enter HelloWorldImpl2.doPrint()
Log after method
CurrentTime = 1446130273737

要想让logHandler在timeHandler前使用有两个办法:

(1)aspect里面有一个order属性,order属性的数字就是横切关注点的顺序,数字越大执行越靠后,后置通知相反。

(2)把logHandler定义在timeHandler前面,Spring默认以aspect的定义顺序作为织入顺序

2、我只想织入接口中的某些方法

修改一下pointcut的expression就好了:

<?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: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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.print*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.do*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>

表示timeHandler只会织入HelloWorld接口print开头的方法,logHandler只会织入HelloWorld接口do开头的方法

3、强制使用CGLIB生成代理

前面说过Spring使用动态代理或是CGLIB生成代理是有规则的,高版本的Spring会自动选择是使用动态代理还是CGLIB生成代理内容,当然我们也可以强制使用CGLIB生成代理,那就是5f4edcee1f0c5735c643ff3ca537e591里面有一个"proxy-target-class"属性,这个属性值如果被设置为true,那么基于类的代理将起作用,如果proxy-target-class被设置为false或者这个属性被省略,那么基于接口的代理将起作用。

The above is the detailed content of Detailed explanation of SpringAop in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn