The concept of AOP

AOP–(Aspect Orient Programming) : Aspect oriented Programming, is a Programming idea, is a complement to OOP (Aspect oriented Programming). AOP takes the same code scattered across different business logic, reconstructs it into a module, and weaves it into the business logic that needs it in a faceted manner.

The book “Spring In Action (4th Edition)” has a graphic illustration illustrating this idea

Why do you need this idea of AOP?

In real development, logs are added to each business code to monitor and record the operation of the business code. At this point, we need to add logs to every place we need to use them. If only one or two or three or four places need to be added, then it is ok to add logs manually, but what about thousands of places? Obviously, manual additions are not appropriate, so some technique is needed to simplify this, and AOP adds logging functionality to the business code in a cross-sectional manner.

AOP terminology

  • Advice: Enhanced processing in an AOP framework. The advice describes when and how the enhanced processing is performed by the aspect.
  • Join point: A Join point is a point at which a section can be inserted during application execution. This point can be a method call or an exception thrown. In Spring AOP, join points are always method calls.
  • Pointcuts: Join points where enhanced processing can be inserted. Use expressions to represent join points to enhance processing
  • Aspect: An Aspect is a combination of advice and pointcuts. Which Aspect = Advice + PointCut
  • Introduction: Introduction allows you to add new methods or attributes to an existing class.
  • Weaving: Weaving is the process of adding enhancement processing to the target object and creating an enhanced object

AspectJ and SpringAOP

AOP is a programming idea that is a goal, the implementation of which is implemented by SpringAOP or AspectJ

AspectJ is a section-oriented framework that extends the Java language. AspectJ defines the AOP syntax, which has a specialized compiler for generating Class files that comply with the Java byte-encoding specification. AspectJ uses static proxies for weaving. Static proxies are compiled using commands provided by the AOP framework to generate AOP proxy classes at compile time, and are therefore also known as compile-time enhancement. Static proxies can be woven at three times: compile time (using AJC), post-compile time (after class files are generated or jar packages are woven), and post-class load time (using the WeavingURLClassLoader). Because this is determined at compile time, the performance is good. AspectJ supports local weaving of fields, methods, constructors, and so on.

SpringAOP is an AOP framework written by Spring in reference to AspectJ. It is based on dynamic proxy implementation, which is implemented using JDK dynamic proxy technology if an interface is used, or CGLIB if a normal class is used. It also relies on SpringIOC for management, so only Spring beans can be AOP. SpringAOP can only be woven at run time, so dynamically generating proxy instances at run time results in poor performance. SpringAOP only supports method weaving and is weak.

Dynamic agent technique

What is dynamic proxy technology? Dynamic proxy technology is to create the proxy object of the target object and enhance the function of the target object method. Proxy objects are not created in the class file at first, but are generated dynamically at run time and then disappear at the end of the program. So when you use dynamic proxies, the object you get is not the original object, but the object that was propped up by the dynamic proxy. This technique can make some functional enhancements to the methods in the original code without modifying the source code, reducing the coupling of the code.

Normal object creation process

The process of creating objects through dynamic proxies

There are two ways to implement dynamic proxies

The first JDK dynamic proxy, used to implement dynamic proxies for interfaces. JDK dynamic Proxy is Java’s own dynamic Proxy technology, mainly involving two classes under the java.lang.Reflect package: Proxy and InvocationHandler. You can dynamically organize business code logic and crosscutting logic together by implementing the InvocationHandler interface to define crosscutting logic and by invoking the code of the target class through reflection.

The second, CGLIB(Code Generation Library), is used to implement dynamic proxies for ordinary classes. It is based on ASM bytecode generation library, through inheritance to carry out dynamic proxy, in the subclass using method interception technology to intercept all the parent class method calls and the potential weaving into crosscutting logic. Because CGLIB is dynamically proxied by inheritance, proxied classes cannot be final

The next step is to use code to further understand these two technologies.

JDK dynamic proxy

// Define the interface
public interface UserService {
    public void getone(a);
    public void gettwo(a);
}
// Implement the interface
public class UserServiceImpl implements UserService {
    @Override
    public void getone(a) {
        System.out.println("I was the first.");
    }

    @Override
    public void gettwo(a) {
        System.out.println("I'm the second."); }}// Implement InvocationHandler interface.
// The InvocationHandler interface is a reflection mechanism to load the methods of the interface implementation class, thus cross-cutting the methods of the proxy object
public class ServiceProxy implements InvocationHandler {
    public Object target;

    public ServiceProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("??????");
        Object invoke = method.invoke(target, args);
        System.out.println("!!!!");
        returninvoke; }}/ / test class
public class ProxyTest {

    public static void main(String[] args) {
        UserService userService=new UserServiceImpl();
        ServiceProxy serviceProxy=new ServiceProxy(userService);
        UserService  userService1= (UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(), 			newClass[]{UserService.class}, serviceProxy); userService1.getone(); userService1.gettwo(); }}/* Result:?? I am the first!!!! ????? I am the second!!!! * /
Copy the code

The newProxyInstance () method has three parameters: ClassLoader loader, Class<? >[] interfaces, InvocationHandler h.

Loader: class loader used to load interfaces

Interfaces: class array of interfaces to dynamically proxy

InvocationHandler: Calls the handler. The invoke method of the proxy object is executed when its method is called. Methods in all proxy objects are intercepted.

CGLIB dynamic proxy

To do this, you need to import two JAR packages, asm and Cglib

// A generic class that needs to implement the proxy
public class OtherClass {
    public void say(a){
        System.out.println("I'm in the middle of business."); }}/ / test class
public class CGLibTest {
    public static void main(String[] args) {
        OtherClass otherClass=new OtherClass();
        OtherClass o = (OtherClass)Enhancer.create(otherClass.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("Implementing CGLIB dynamic proxy");
                Object invoke = method.invoke(otherClass, objects);
                returninvoke; }}); o.say(); }}/* Result implements CGLIB dynamic proxy I am processing business */
Copy the code

From the above code, dynamic proxy is done through the create method under the Enhancer class. This method takes two arguments, Class type and Callback Callback.

Type: the class that needs to implement dynamic proxies

Callback: An interface that can be understood as logic to be executed when a method of the generated proxy class is called.

Its implementation classes are as follows

  1. MethodInterceptor
  2. NoOp
  3. LazyLoader
  4. Dispatcher
  5. InvocationHandler
  6. FixedValue

If you want to know more, you can do it yourself.

SpringAOP code implementation

SpringAOP has two ways of implementing code. One is an XML file, which has always been annotation-based. As long as you learn how to write in XML, annotations are easy, so the rest of the code will be written in XML files.

It needs to be introduced before the code is written

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>
Copy the code

First, enable AOP support. There are two ways to do this. One is through AOP: AspectJ-AutoProxy/tag, and the other is through the @enableAspectJAutoProxy annotation.

Here’s a simple test

// Define the interface
public interface UserService {
    public void info(a);
}
// Define the implementation class of the interface
public class UserServiceImpl implements UserService{
    @Override
    public void info(a) {
        System.out.println("Info"); }}// Define the section
public class AJOne {
    public void say(a){
        System.out.println("I'm number one."); }}Copy the code
<! Write XML code --> <! < AOP :aspectj-autoproxy/> <! Class defined aspects -- -- -- > < bean id = "Ajone" class = "com. Itheima. Aop. Ajone" / > <! IOC the implementation class of the interface. Said earlier SpringAOP proxy objects must be SpringBean, so need to registered Bean - > < Bean id = "userService" class = "com. Itheima. Service. UserServiceImpl" / > <! --> < AOP :config> <! Configure AOP pointcut, Used to find the need for the agent's method -- -- > < aop: pointcut id = "pointcutOne expression" = "execution (* com. Itheima. Service. UserServiceImpl. Info (..) ) "/ > <! Aop :aspect ref="Ajone"> <aop:aspect ref="Ajone"> Advice configuration <aop:before method="say" pointcut-ref="pointcutOne"></aop:before> </aop:aspect> </aop:config>Copy the code
// Write the test class
public class Test01 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class); userService.info(); }}/* Result: I am in first place oh Info */
Copy the code

Since SpringAOP is implemented through either a JDK proxy or a CGLIB proxy, what is used by default?

Use DEBUG to solve the problem

CGLIB is a JDK proxy that is used by default. You can modify this with the proxy-target-class attribute in the AOP :config tag, setting it to true, and it becomes a CGLIB implementation.

This is the simplest implementation of SpringAOP, and some of its capabilities will be explained in more detail.

Advice – notification

As mentioned earlier, the advice describes when and how the enhanced processing is performed by the aspect. There are five kinds of notification in SpringAOP, which are Before, After returning, Around, After throwing and After.

The location of the five notifications and the order in which they are executed are described in a piece of code

try{
    AroundBefore();// Wrap around the notification header
    Before();// Pre-notification
    method();// Business code
    AroundAfter();// Wrap around the notification tail
    After();// post notification
}catch(Throwable t){
    AfterThrowing();// Exception notification
}finally{
    AfterReturning();// Final notification
}
Copy the code

Before code implementation, first accept two classes, one is JoinPoint, and the other is a subclass of JoinPoint ProceedingJoinPoint.

JoinPoint encapsulates the facet information in SpringAop. Add this parameter to the facet method to obtain the JoinPoint object that encapsulates the information of the method.

The method in JoinPoint is as follows

The method name function
Signature getSignature(); Gets the object that encapsulates the signature information. In this object, you can get the target method name, the Class of the owning Class, and other information
Object[] getArgs(); Gets the parameter object passed to the target method
Object getTarget(); Gets the proxied object
Object getThis(); Getting a proxy object

Because ProceedingJoinPoint is a subclass of JoinPoint, it can use all of JoinPoint’s methods. It also adds two methods

Object proceed(a) throws Throwable // Execute the target method
Object proceed(Object[] var1) throws Throwable // A new argument is passed to execute the target method
Copy the code

ProceedingJoinPoint can only be used when surrounding notifications

The next step is to code each of the five notifications

Before notice

Weave before the method is implemented

// Define the interface
public interface UserService {
    public void info(a);
}
// Define the implementation class of the interface
public class UserServiceImpl implements UserService{
    @Override
    public void info(a) {
        System.out.println("Info"); }}// Define the section
public class AJOne {
   public void before(JoinPoint joinPoint){
        System.out.println("Get method name of proxy object"+joinPoint.getSignature().getName());
        System.out.println("Get the parameters of the method in the proxy object"+ Arrays.toString(joinPoint.getArgs()));
        System.out.println("Get the proxied object"+joinPoint.getTarget().toString());
        System.out.println("Get proxy object"+joinPoint.getThis().toString());
        System.out.println("Advance notice"); }}Copy the code
<bean id="Ajone" class="com.itheima.aop.AJOne"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
   <aop:pointcut id="pointcutOne" expression="execution(* com.itheima.service.UserServiceImpl.info(..) )"/>
     <aop:aspect ref="Ajone">
       <aop:before method="before" pointcut-ref="pointcutOne"></aop:before>
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test02 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class); userService.info(); }}/ * results: Obtain the proxy object method name info for method parameters in a proxy object [] to obtain is com proxy objects. Itheima. Service. 20 d28811 UserServiceImpl @ Get a proxy object com. Itheima. Service. 20 d28811 UserServiceImpl @ front notify Info * /
Copy the code

AfterReturning

Woven after the method is implemented, the notification gets the return value of the method

// Define the interface
public interface UserService {
    public int add(int a,int b);
}
// Define the implementation class of the interface
public class UserServiceImpl implements UserService{
   @Override
    public int add(int a,int b) {
       returna+b; }}// Define the section
public class AJOne {
    public void afterreturning(Object val){
        System.out.println("Method return value obtained after notification"+val); }}Copy the code
<bean id="Ajone" class="com.itheima.aop.AJOne"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
	<aop:pointcut id="pointcutTwo" expression="execution(* com.itheima.service.UserServiceImpl.add(..) )"/>
    <aop:aspect ref="Ajone">
        <! Returning a value to a method parameter -->
      <aop:after-returning method="afterreturning" pointcut-ref="pointcutTwo" returning="val"/>
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test03 {
    public static void main(String[] args) {
       ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        int i = userService.add(5.2); System.out.println(i); }}/* Result: the method returns a value of 7, 7 */
Copy the code

Circular notification (Around)

Weaving takes place before and after the method implementation, which relies on the Proceed () method in proceedingJoinPoint

// Define the interface
public interface UserService {
    public int add(int a,int b);
}
// Define the implementation class of the interface
public class UserServiceImpl implements UserService{
   @Override
    public int add(int a,int b) {
       returna+b; }}// Define the section
public class AJOne {
    public int around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Surround pre-notification");
        Integer proceed = (Integer)proceedingJoinPoint.proceed();// The surround notification must use the proceed method before the target object's method can be used. We can get the return value of the target object's method and modify it
        System.out.println(proceed);
        System.out.println("Surround back notification");
        return 10; }}Copy the code
<bean id="Ajone" class="com.itheima.aop.AJOne"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
  <aop:pointcut id="pointcutThree" expression="execution(* com.itheima.service.UserServiceImpl.add(..) )"/>
    <aop:aspect ref="Ajone">
            <aop:around method="around" pointcut-ref="pointcutThree" />
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test04 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        int i = userService.add(5.2); System.out.println(i); }}/* Result: surround pre-notification 7 surround post-notification 10 */
Copy the code

As a result, we did modify the method return value of the proxy object.

Exception notification (AfterThrowing)

Executed when the proxy object’s method throws an exception

// Define the interface
public interface UserService {
    public int division(int a,int b);
}
public class UserServiceImpl implements UserService{
    @Override
    public int division(int a, int b) {
        returna/b; }}// Define the section
public class AJOne {
    public void throwing(Throwable t){
        System.out.println("Exception notification"); System.out.println(t.getMessage()); }}Copy the code
<bean id="Ajone" class="com.itheima.aop.AJOne"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
 <aop:pointcut id="pointcutFour"expression="execution(*com.itheima.service.UserServiceImpl.division(..) )"/>
 <aop:aspect ref="Ajone">
     <! -- Throwing property is the name of the exception class in the method -->
     <aop:after-throwing method="throwing" pointcut-ref="pointcutFour" throwing="t"/>
 </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test05 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        int i = userService.division(5.0); System.out.println(i); }}/* Result: exception notification/by zero */
Copy the code

Final notice (After)

Executes regardless of whether the code has exceptions or not

// Define the interface
public interface UserService {
    public int division(int a,int b);
}
public class UserServiceImpl implements UserService{
    @Override
    public int division(int a, int b) {
        returna/b; }}// Define the section
public class AJOne {
    public void after(a){
        System.out.println("Final notice"); }}Copy the code
<bean id="Ajone" class="com.itheima.aop.AJOne"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"
<aop:config>
<aop:pointcut id="pointcutFive" expression="execution(* com.itheima.service.UserServiceImpl.division(..) )"/>
   <aop:aspect ref="Ajone">
     <aop:after method="after" pointcut-ref="pointcutFive"/>
   </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test06 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        int i = userService.division(5.0); System.out.println(i); }}/ * results: eventually notice the Exception in the thread "is the main" Java. Lang. ArithmeticException: / by zero at com.itheima.service.UserServiceImpl.division(UserServiceImpl.java:22) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) at com.sun.proxy.$Proxy4.division(Unknown Source) at com.itheima.test.Test06.main(Test06.java:14) Process finished with exit code 1 */
Copy the code

The result shows that the final notification will be executed even if there is an exception, so the final notification is usually used for tasks such as closing the connection or clearing the resource.

Pointcut – point

Join points for enhanced processing can be inserted. Use expressions to represent join points to enhance processing. There are several kinds of expressions

Execution () : The execution method used to match the join point

Arg () : restricts execution methods to join points matching arguments of the specified type

@args() : Execution method that restricts join point matching parameters to be annotated by specified annotations

Target () : limits the join point to match a class whose target object is of the specified type

@target() : Restrict join points to match specific execution objects that correspond to classes with annotations of the specified type

Within () : limits the join point to match the specified type

@WITHIN () : Limits the join point to match the type annotated by the specified annotation

This: Restricts join points to match AOP proxy Bean references to classes of the specified type

Annotation: Restrict matches with specified annotation join points

These expressions can be done with or logic operations, in XML as && and | |,! Has a special meaning, so use AND, OR, not instead in the XML file

Since the execution() expression is more common, we will discuss the use of other expressions and, finally, the execution() expression

arg()

// Define the interface
public interface UserService {
    public void info(String s1,String s2);
    public void info(int num);
}
// Define the implementation class
public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) { System.out.println(num); }}// Define the section class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
    <! -- arg expression is used to match methods whose parameters are two strings -->
  <aop:pointcut id="argTest" expression="args(java.lang.String,java.lang.String)"/>
  <aop:aspect ref="beforeAdvice">
     <aop:before method="problem" pointcut-ref="argTest"/>
  </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test07 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cc.getBean("userService", UserService.class);
        userService.info("One"."Two");
        userService.info(50); }}/* One==Two 50 */
Copy the code

The results show that only the join points that conform to ARG expression are cut.

@args()

An @args expression takes only one argument, which must be an object and must have an annotation defined in the @args expression to be cut in

Since the expression requires an annotation, you can define a custom annotation or use someone else’s annotation

// note that arguments can only be objects, so they apply to classes
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Args {
}
// Define a class that uses custom annotations
@Args
public class Car {
    @Override
    public String toString(a) {
        return "car!!!"; }}// Define the interface
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Define the interface implementation class
public class UserServiceImpl implements UserService{
     @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }
    @Override
    public void info(Car car) { System.out.println(car); }}// Define the section
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
    <! < span style = "color: RGB (50, 50, 50); color: RGB (50, 50, 50);
  <aop:pointcut id="Args" expression="@args(com.itheima.annotated.Args)"/>
  <aop:aspect ref="beforeAdvice">
    <aop:before method="problem" pointcut-ref="Args"/>
  </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test08 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cc.getBean("userService", UserService.class);
        userService.info("One"."Two");
        userService.info(50);
        userService.info(newCar()); }}/* Result: One==Two 50 * /
Copy the code

target()

// Define two interfaces for comparison
public interface PeopleService {
    public void say(int num);
}
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Interface implementation class
public class PeopleServiceImpl implements PeopleService{
    @Override
    public void say(int num) { System.out.println(num); }}public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}/ / cut class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<bean id="peopleService" class="com.itheima.service.PeopleServiceImpl"/>
<aop:config>
    <! The fully qualified name in target can be either the interface or the implementation class of the interface.
  <aop:pointcut id="target" expression="target(com.itheima.service.UserService)"/>
  <aop:aspect ref="beforeAdvice">
      <aop:before method="problem" pointcut-ref="target"/>
  </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Tets09 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        PeopleService peopleService = cp.getBean("peopleService", PeopleService.class);
        peopleService.say(20);
        System.out.println("= = = = = = = = = = = = = = =");
        userService.info(20);
        userService.info(new Car());
        userService.info("first"."second"); }}/* Result: 20 =============== pre-notification 20 pre-notification car!! First ==second */
Copy the code

With result return, the target expression is only woven for the specified class, and not for classes that are not specified.

@target

This expression is used to weave in classes that use the specified annotation, starting with a custom annotation

// Custom annotations
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Targets {
}
// Define two interfaces for comparison
public interface PeopleService {
    public void say(int num);
}
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Interface implementation class
@Targets
public class PeopleServiceImpl implements PeopleService{
    @Override
    public void say(int num) { System.out.println(num); }}public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}/ / cut class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<bean id="peopleService" class="com.itheima.service.PeopleServiceImpl"/>
<aop:config>
    <! --@taget specifies an annotation that applies only to the implementation class of the interface.
  <aop:pointcut id="targets" expression="@target(com.itheima.annotated.Targets)"/>
  <aop:aspect ref="beforeAdvice">
     <aop:before method="problem" pointcut-ref="targets"/>
  </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Tets10 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        PeopleService peopleService = cp.getBean("peopleService", PeopleService.class);
        peopleService.say(20);
        System.out.println("= = = = = = = = = = = = = = =");
        userService.info(20);
        userService.info(new Car());
        userService.info("first"."second"); }}/* Result: Pre-notification 20 =============== 20 car!! first==second */
Copy the code

within()

This expression also works on classes, but it is much more extensive than target, where within can weave into all classes in a package, whereas target can only weave into a specific class

// Define two interfaces under one package
public interface PeopleService {
    public void say(int num);
}
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Two interface implementation classes
public class PeopleServiceImpl implements PeopleService{
    @Override
    public void say(int num) { System.out.println(num); }}public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}/ / cut class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<bean id="peopleService" class="com.itheima.service.PeopleServiceImpl"/>
<aop:config>
<! Com.itheima. service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima.service: com.itheima. * -- - >
    <aop:pointcut id="within" expression="within(com.itheima.service.*)"/>
    <aop:aspect ref="beforeAdvice">
        <aop:before method="problem" pointcut-ref="within"/>
    </aop:aspect>
</aop:config>
Copy the code
/ / test
public class Test11 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        PeopleService peopleService = cp.getBean("peopleService", PeopleService.class);
        peopleService.say(20);
        System.out.println("= = = = = = = = = = = = = = =");
        userService.info(20);
        userService.info(new Car());
        userService.info("first"."second"); }}Prior notification / * results: 20 = = = = = = = = = = = = = = = pre notice 20 front car!!!!!! First ==second */
Copy the code

@within()

// Custom annotations
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Within {
}
// Define two interfaces under one package
public interface PeopleService {
    public void say(int num);
}
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Two interface implementation classes
public class PeopleServiceImpl implements PeopleService{
    @Override
    public void say(int num) { System.out.println(num); }}public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}/ / cut class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<bean id="peopleService" class="com.itheima.service.PeopleServiceImpl"/>
<aop:config>
    <aop:pointcut id="within" expression="@within(com.itheima.annotated.Within)"/>
    <aop:aspect ref="beforeAdvice">
        <aop:before method="problem" pointcut-ref="within"/>
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test12{
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        PeopleService peopleService = cp.getBean("peopleService", PeopleService.class);
        peopleService.say(20);
        System.out.println("= = = = = = = = = = = = = = =");
        userService.info(20);
        userService.info(new Car());
        userService.info("first"."second"); }}/* Result: Pre-notification 20 =============== 20 car!! first==second */
Copy the code

There is no difference between @target and @within, but there is a difference. We can find the difference in code.

Difference between @target and @within

// Define two annotations
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Targets {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Within {
}
// Define one parent class and two subclasses
@Within
@Targets
public class Man {
    public void speak(a){
        System.out.println("Manspeak!!!");
    }
    public void say(a){
        System.out.println("say!!!"); }}public class NoMan extends Man{
    @Override
    public void say(a) {
        System.out.println("NoManSay"); }}public class Human extends Man{
    @Override
    public void speak(a) {
        System.out.println("Humanspeak"); }}// Define an aspect
public class BeforeAdvice {
    public void target(a){
        System.out.println("Using the @ target");
    }
    public void within(a){
        System.out.println("Using the @ with"); }}Copy the code
<bean id="huMan" class="com.itheima.service.Human"/>
<bean id="man" class="com.itheima.service.Man"/>
<bean id="noMan" class="com.itheima.service.NoMan"/>
<aop:config>
    <aop:pointcut id="targets" expression="@target(com.itheima.annotated.Targets)"/>
    <aop:pointcut id="within" expression="@within(com.itheima.annotated.Within)"/>
    <aop:aspect ref="beforeAdvice">
        <aop:before method="target" pointcut-ref="targets"/>
        <aop:before method="within" pointcut-ref="within"/>
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test13 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        Man man = cp.getBean("man", Man.class);
        NoMan noMan = cp.getBean("noMan", NoMan.class);
        HuMan huMan = cp.getBean("huMan", Human.class);
        man.say();
        man.speak();
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        huMan.say();
        huMan.speak();
        System.out.println("= = = = = = = = = = = = = ="); noMan.say(); noMan.speak(); }}/* Result: use @target with @say!! Use @target use @with Manspeak!! =================== use @with say!! Humanspeak = = = = = = = = = = = = = = NoManSay using the @ with Manspeak!!!!!! * /
Copy the code

Using the above code and tests, we found that @targe will only knit into classes that are specified for annotation, while @within will only knit into classes that are specified for annotation. Its subclasses can also knit into classes that are not overridden.

this()

// Define two interfaces under one package
public interface PeopleService {
    public void say(int num);
}
public interface UserService {
    public void info(String s1, String s2);
    public void info(int num);
    public void info(Car car);
}
// Two interface implementation classes
public class PeopleServiceImpl implements PeopleService{
    @Override
    public void say(int num) { System.out.println(num); }}public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}/ / cut class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<bean id="peopleService" class="com.itheima.service.PeopleServiceImpl"/>
<aop:config>
    <! If the expression is an interface, then the interface's implementation class is woven in, but the interface can only have one implementation class. If it is a class, it will be woven in using CGLIB-->
    <aop:pointcut id="this" expression="this(com.itheima.service.UserService)"/>
    <aop:aspect ref="beforeAdvice">
        <aop:before method="problem" pointcut-ref="this"/>
    </aop:aspect>
</aop:config>
Copy the code

@annotation()

// Define a custom annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Method {
}
// Define an interface
public interface UserService {
    public void info(String s1, String s2);
    public void info( int num);
    public void info(Car car);
}
// Define the interface implementation class
public class UserServiceImpl implements UserService{

    @Override
    public void info(String s1, String s2) {
        System.out.println(s1+"= ="+s2);
    }

    @Override
    @Method
    public void info(int num) {
        System.out.println(num);
    }

    @Override
    public void info(Car car) { System.out.println(car); }}// Define the section class
public class BeforeAdvice {
    public void problem(a){
        System.out.println("Advance notice"); }}Copy the code
<bean id="beforeAdvice" class="com.itheima.AJ.BeforeAdvice"/>
<bean id="userService" class="com.itheima.service.UserServiceImpl"/>
<aop:config>
    <! Weave in the method with the specified annotation -->
    <aop:pointcut id="annotation" expression="@annotation(com.itheima.annotated.Method)"/>
    <aop:aspect ref="beforeAdvice">
        <aop:before method="problem" pointcut-ref="annotation"/>
    </aop:aspect>
</aop:config>
Copy the code
/ / test class
public class Test16 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("/ApplicationContext.xml");
        UserService userService = cp.getBean("userService", UserService.class);
        userService.info(20);
        userService.info(new Car());
        userService.info("first"."second"); }}/* Result: pre-notification 20 car!! first==second */
Copy the code

execution()

This expression is one of the most commonly used expressions, it has many ways of weaving, it needs to focus on learning.

“Execution (modifiers – the pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) This is the formula for an execution expression, which consists of a number of parts that are explained in turn

modifiers-pattern? Modifier match, used to match the specified modifier join point,? If the expression is not written, all modifiers will be matched. *** ** also means all modifiers will be matched

Ret-type-pattern: return value matching, used to match the specified return value type join point. The match must exist and no error is reported. Any return value can be represented by *****

Declaring – type – the pattern? : declares a type match, used to match the join points of the classes specified by the package name. This match may not exist, if it does not exist, it will match the join points of all classes under all packages

Name-pattern: name match. It is used to match the join point with the specified name. The match must exist and no error is reported. You can use * for any name

Param-pattern: parameter matching, used to match the connection point of a specified parameter. The matching must exist and no error is reported. You can use.. Indicates any number of parameters of any type. ***** indicates one parameter of any type

Throws -pattern: exception matching, used to match specified exception join points. This matching is optional

Because there are so many different ways to use an execution() expression, the content of the expression is analyzed without code

execution(* *(..) )Copy the code

This expression represents a join point that matches any modifier, any return value type, any parameter with any name in all classes under any package name. The first represents the return value type, and the second represents any name. Since modifiers and packages can be left unchecked, and unwritten represents any, this expression matches all join points.

execution(public* * (..) )Copy the code

This expression represents a join point that matches any parameter of any name in any class of any return value type of any public modifier, any package name.

execution(public int* (..) )Copy the code

This expression represents a join point that matches any parameter of any name in all classes of any package name whose public modifier returns a value of type int.

execution(* com.itheima.service.UserService.*(..) )Copy the code

This expression means to match. Com itheima. Service. UserService under the class of all methods

execution(* com.itheima.service.*.*(..) )Copy the code

This expression matches join points in all classes under the com.itheima.service package

execution(* *.service.*.*(..) )Copy the code

This expression matches all classes in the com.service/cn.service package

execution(* *.. service.*.*(..) )Copy the code

This expression represents join points in all classes under the matching service package

execution(* *.. service.. * (..) )Copy the code

This expression matches join points in all classes under the Service package and its subpackages

execution(* com.itheima.service.*.say(..) )Copy the code

This expression matches join points named SAY in all classes in the com.itheima.service package

execution(* com.itheima.service.*.*(String))
Copy the code

This expression matches join points with method arguments of type String in all classes in the com.itheima.service package

execution(* com.itheima.service.*.*(String,*))
Copy the code

This expression matches join points of any type of method parameter type of any class in the com.itheima.service package

execution(* com.itheima.service.*.*(String,..) )Copy the code

This expression matches any class in the com.itheima.service package whose method parameter type is String, followed by any number of join points of any type.

Execution is a combination of execution within and target. Within and target can indicate execution as well

There are many more ways to write the executio() expression, and you can explore them on your own.

Conclusion:

AOP is a programming idea that complements OOP. It is mainly used to process some crosscutting system-level services, such as log collection, transaction management, security check, cache, and object pool management

2, there are two ways to implement AOP ideas, one is AspectJ, one is SpringAOP. Both are proxy-based, with AspectJ based on static proxies and SpringAOP based on dynamic proxies

SpringAOP’s dynamic proxy is divided into two types, one based on interface and one based on class

4. Because SpringAOP is based on dynamic proxies, it has a performance impact at runtime

5. Aspect is an important aspect of SpringAOP. It consists of pointcut and advice