Spring Boot 3, Spring 6 & Hibernate for Beginners
To uninstall the JDK on macOS:
You must have Administrator privileges.
Note:
Do not attempt to uninstall Java by removing the Java tools from /usr/bin
. This directory is part of the system software and any changes will be reset by Apple the next time that you perform an update of the OS.
- Go to
/Library/Java/JavaVirtualMachines
. - Remove the directory whose name matches the following format by executing the
rm
command as a root user or by using thesudo
tool:/Library/Java/JavaVirtualMachines/jdk-16.interim.update.patch.jdk
For example, to uninstall 16 Interim 0 Update 0 Patch 0:
$ rm -rf jdk-16.jdk
Maven solution
- Tell Maven projects you are working with (dependencies)
- Spring, Hibernate etc…
- Maven will go out and download the JAR files for those projects for you
- And Maven will make those JAR files available during compile / run
- Think of Maven as your helper / personal shopper
To change port tomcat
server.port=9000
To start running
package com.madindo.springboot.mycoolapp.rest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FunRestController {
@GetMapping("/")
public String sayHello() {
return "Hello World";
}
}
What is Maven?
- Maven is a Project Management tool
- Most popular use of Maven is for build management and dependencies
Maven Solution
- Tell maven the projects you are working with (dependencies) - Spring, Hibernate etc ...
- Maven will go out and download the JAR files for those projects for you
- and maven will make those JAR files available during compile / run
- Think of Maven as your friendly helper / personal shopper.
Project Coordinates - Elements
Group ID - Name of company, group or organization
Artifact ID - Name for this project: mycoolapp
Version - A specific release version like : 1.0, 1.6, 2.0 … If project is under active development then : 1.0-SNAPSHOT
<groupId>com.madindo</groupId>
<artifactId>madindo</artifactId>
<version>1.0.FINAL</version>
Springboot dev tools
Solution: Spring boot Dev Tools
- spring-boot-devtools to the rescue!
- Automatically restarts your application when code is updated
- Simply add the dependency to your POM file
- No need to write additional code
- For intelliJ, need to set additional configurations… will discuss shortly
IntelliJ Community Edition - devtools
- IntelliJ Community Edition does not support Devtools by default
- Select: Preferences > Build, Execution, Deployment > compiler
- Check box: Build project automatically
- Additional setting
- Select : Preferences > Advanced Settings
- Checkbox : Allow auto make to …
Springboot actuator
//pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
//application.properties
management.endpoints.web.exposure.include=health,info
management.info.env.enabled=true
//application.properties
info.app.name="My Super Cool App"
info.app.description="A crazy fun app"
info.app.version="1.0.0"
//application.properties
//to expose all endpoints
management.endpoints.web.exposure.include=*
//endpoints
/actuator/beans
/actuator/threaddump
/actuator/mappings
Command line
./mvnw package
java -jar mycoolapp-0.0.1-SNAPSHOT.jar
//another way
./mvnw spring-boot:run
Custom application properties
# application.properties
#
# Define my properties
#
coach.name="Mickey Mouse"
team.name="The Mouse Club"
# FunRestController
@Value("${coach.name}")
private String coachName;
@Value("${team.name}")
private String teamName;
Spring boot server
#
# Set the context path of the application
# All request should be prefixed with /mycoolapp
#
server.servlet.context-path=/mycoolapp
Inversion of control
The approach of outsourcing the construction and management of objects.
Spring Container
- Primary functions
- Create and manage objects (Inversion of Control)
- Inject object dependencies (Dependency Injection)
Dependency Injection
The dependency inversion principle.
The client delegates to another object the responsibility of providing its dependencies.
Injection Types - Which one to use?
- Construction injection
- Use this when you have required dependencies
- Generally recommended by the spring.io development team as first choice
- Setter Injection
- Use this when you have optional dependencies
- If dependency is not provided, your app can provide reasonable default logic
What is Spring AutoWiring
- For dependency injection, Spring can use autowiring
- Spring will look for a class that matches
- matches by type: class or interface
- Spring will inject it automatically … hence it is autowired
Autowiring Example
- Injecting a coach implementation
- Spring will scan for @Components
- Any one implements the Coach interface???
- If so, let’s inject them. For example: CricketCoach
@Component annotation
- @Component marks the class as a spring bean
- A spring bean is just regular java class that is managed by Spring
- @Component also makes the bean available for dependency injection.
Constructor Injection
https://start.spring.io/
pick maven
update the fields
dependencies - devtools & spring web
generate and download
//open folder
//create interface in src/main/java/com.m.m
public interface Coach {
String getDailyWorkout();
}
//create class CricketCoach
@Component
public class CricketCoach implements Coach{
@Override
public String getDailyWorkout() {
return "Practice face bowling for 15 minutes!!!!";
}
}
//create demoController
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(Coach theCoach){
myCoach = theCoach;
}
@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}
Spring for enterprise applications
- Spring is targeted for enterprise, real-time / real-world applications
- Spring provides features such as
- Database access and Transactions
- REST APIs and Web MVC
- Security
- etc…
Component scanning
Scanning for component classes
- Spring will scan your java classes for special annotations
- @Component, etc …
- Automatically register the beans in the Spring container
More on component Scanning
- By default, Spring boot starts component scanning
- From same package as your main Spring boot application
- also scans sub-packages recursively
- This implicitly defines a base search package
- Allows you to leverage default component scanning
- No need to explicitly reference the base package name
We want to get the util from outside of springcoredemo and that is to reference that from the SpringcoredemoApplication using @SpringBootApplication
@SpringBootApplication(
scanBasePackages = {
"com.madindo.springcoredemo",
"com.madindo.util"
}
)
Setter Injection
// when changing the name setCoach to something it should be still work
@Autowired
public void setCoach(Coach theCoach){
myCoach = theCoach;
}
Field Injection
Spring Injection Types
- Recommended by the spring.io development team
- Constructor injection: required dependencies
- Setter Injection: optional dependencies
- Not recommended by the spring.io development team
- Field Injection
Field injection … no longer cool
- In the early days, field injection was popular on Spring projects
- In recent years, it has fallen out of favor
- In general, it makes the code harder to unit test
- As a result, the spring.io team does not recommend field injection
- However, you will still see it being used on legacy projects
Qualifiers
public DemoController(@Qualifier("baseballCoach") Coach theCoach) {
myCoach = theCoach;
}
Primary
Which one: @Primary or @Qualifier?
- @Primary leaves it up to the implementation classes
- Could have the issue of multiple @Primary classes leading to an error
- @Qualifier allows to you be very specific on which bean you want
- In general, I recommend using @Qualifier
- More specific
- Higher priority
Lazy initialization
- Instead of creating all beans up front, we can specify lazy initialization
- A bean will only be initialized in the following cases:
- It is needed for dependency injection
- Or it is explicitly requested
- Add the @Lazy annotation to a given class
- Advantages
- Only create objects as needed
- May help with faster startup time if you have large number of components
- Disadvantages
- If you have web related components like @RestController, not created until requested
- May not discover configuration issues until too late
- Need to make sure you have enough memory for all beans once created
// use @Lazy for each class or global
// global application.properties
spring.main.lazy-initialization=true
Bean Scope
Refresher: What is a singleton?
- Spring Container creates only one instance of the bean, by default
- It is cached in memory
- All dependency injections for the bean
- Will reference the SAME bean
Scope | Description |
singleton | create a single shared instance of the bean . Default scope. |
prototype | create a new bean instance for each container request. |
request | scoped to an HTTP web request. Only used for web apps. |
session | scoped to an HTTP web request. Only used for web apps. |
global-session | scoped to a global HTTP web session. Only used for web apps. |
Check if it’s singleton
public DemoController(
@Qualifier("cricketCoach") Coach theCoach,
@Qualifier("cricketCoach") Coach theAnotherCoach
) {
myCoach = theCoach;
anotherCoach = theAnotherCoach;
}
@GetMapping("/check")
public String check() {
return "Comparing beans: myCoach == anotherCoach, " + (myCoach == anotherCoach);
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CricketCoach implements Coach{
public CricketCoach() {
System.out.println("In constructor : " + getClass().getSimpleName());
}
@Override
public String getDailyWorkout() {
return "Practice face bowling for 15 minutes!!!! :DDD";
}
}
Bean lifecycle
Bean lifecycle methods / hooks
- you can add custom code during bean initialization
- calling custom business logic methods
- setting up handles to resources (db, sockets, file etc)
- You can add custom code during bean destruction
- Calling custom business logic method
- Clean up handles to resources (db, sockets, files etc)
//CricketCoach
@PostConstruct
public void doMyStartupStuff(){
System.out.println("In doMyStartupStuff() : " + getClass().getSimpleName());;
}
@PreDestroy
public void doMyCleanupStuff(){
System.out.println("In doMyCleanupStuff() : " + getClass().getSimpleName());;
}
Java beans configuration
Hibernate
What is JPA
- Jakarta Persistence Api (JPA) … previously known as java persistence API
- Standard API for object-to-relational-mapping (ORM)
- Only a specification
- Defines a set of interfaces
- Requires an implementation to be usable
What are benefits of JPA
- By having a standard API, you are not locked to vendor’s implementation
- Maintain portable, flexible code by coding to JPA spec (interfaces)
- Can theoretically switch vendor implementations
- For example, if vendor abc stops supporting their product
- you could switch to vendor xyz without vendor lock in
Automatic Data Source Configuration
- In spring boot, hibernate is the default implementation of JPA
- EntityManager is main component for creating queries etc …
- EntityManager is from Jakarta Persistence API (JPA)
// use https://start.spring.io/
// add Maven, 3.2.0 dep mysql driver, spring data jpa
// application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/test_student_tracker
spring.datasource.username=springstudent
spring.datasource.password=Madindo123!@#
spring.main.banner-mode=off
logging.level.root=warn
@Bean
public CommandLineRunner commandLineRunner(String[] args) {
return runner -> {
System.out.println("Hello world");
};
}
Entity Class
- At a minimum, the entity class
- Must be annotated with @Entity
- Must have a public or protected no-argument constructor
- The class can have other constructs
Constructors in Java - refresher
- Remember about constructors in Java
- If you don’t declare any constructors
- Java will provide a no-argument constructor for free
- If you declare constructors with arguments
- then you do not get a no argument constructor for free
- in this case, you have to explicitly declare a no-argument constructor
@Column - optional
- Actually, the use of @Column is optional
- if not specified, the column name is the same name as Java field
- In general, I don’t recommend this approach
- If you refactor the java code, then it will not match existing database columns
- This is breaking change and you will need to update database column
- Same applies to @Table, database table name is same as the class
ID generation strategies
Name | Description |
GenerationType.AUTO | Pick an approriate strategy for the particular database |
GenerationType.IDENTITY | Assign primary keys using database identity |
GenerationType.SEQUENCE | Assign primary keys using a database sequence |
GenerationType.TABLE | Assign primary keys using an underlying database table to ensure uniqueness |
// create new package entity and new file called Student
package com.madindo.cruddemo.entity;
import jakarta.persistence.*;
@Entity
@Table(name="student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="email")
private String email;
public Student() {
}
public Student(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
}
Spring @Transactional
- Spring provides an @Transactional annotation
- Automagically begin and end a transaction for your JPA code
- No need for you to explicitly do this in your code
- This Spring magic happens behind the scenes
Specialized Annotation for DAOs
- Applied to DAO implementations
- Spring will automatically register DAO implementation
- Thanks to component-scanning
- Spring also provides translation of any JDBC related exceptions
CREATE
// create new package dao
// create interface StudentDao
package com.madindo.cruddemo.dao;
import com.madindo.cruddemo.entity.Student;
public interface StudentDAO {
void save(Student theStudent);
}
---
package com.madindo.cruddemo.dao;
import com.madindo.cruddemo.entity.Student;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class StudentDaoImpl implements StudentDAO{
private EntityManager entityManager;
@Autowired
public StudentDaoImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
@Transactional
public void save(Student theStudent) {
entityManager.persist(theStudent);
}
}
READ
Query
JPA Query Language (JPQL)
- Query language for retrieving objects
- Similar in concept to SQL
- where,like, orderby, join, in, etc…
- However, JPQL is based on entity name and entity fields
//student DAO interface
Student findById(Integer id);
List<Student> findAll();
List<Student> findByLastName(String theLastName);
---
// studentDAOImpl
public Student findById(Integer id) {
return entityManager.find(Student.class, id);
}
@Override
public List<Student> findAll() {
TypedQuery<Student> theQuery = entityManager.createQuery("From Student order by firstName asc", Student.class);
return theQuery.getResultList();
}
@Override
public List<Student> findByLastName(String theLastName) {
TypedQuery<Student> theQuery = entityManager.createQuery(
"From Student WHERE lastName=:theData", Student.class);
theQuery.setParameter("theData", theLastName);
return theQuery.getResultList();
}
---
//
queryForStudent(studentDAO);
queryForStudentsByLastName(studentDAO);
private void queryForStudentsByLastName(StudentDAO studentDAO) {
List<Student> theStudent = studentDAO.findByLastName("Duck");
for (Student tempStudent : theStudent) {
System.out.println(tempStudent);
}
}
private void queryForStudent(StudentDAO studentDAO) {
List<Student> theStudent = studentDAO.findAll();
for (Student tempStudent : theStudent) {
System.out.println(tempStudent);
}
}
private void readStudent(StudentDAO studentDAO) {
Student tempStudent = new Student("Daffy", "Duck", "daffy@madindo.com");
studentDAO.save(tempStudent);
int theId = tempStudent.getId();
Student myStudent = studentDAO.findById(theId);
System.out.println("Found the student " + myStudent);
}
// StudentDAO
void update(Student theStudent);
----
// StudentDAOImpl
@Override
@Transactional
public void update(Student theStudent) {
entityManager.merge(theStudent);
}
----
//
updateStudent(studentDAO);
private void updateStudent(StudentDAO studentDAO) {
int studentId = 1;
Student myStudent = studentDAO.findById(studentId);
myStudent.setFirstName("Scooby");
studentDAO.update(myStudent);
System.out.println("Updated Student : " + myStudent);
}
DELETE
//CruddemoApplication
deleteStudent(studentDAO);
deleteAllStudent(studentDAO);
//StudentDAO
int deleteAll();
void delete(Integer Id);
@Override
@Transactional
public int deleteAll() {
int numRowsDeleted = entityManager.createQuery("DELETE FROM Student").executeUpdate();
return numRowsDeleted;
}
@Override
@Transactional
public void delete(Integer Id) {
Student theStudent = entityManager.find(Student.class, Id);
entityManager.remove(theStudent);
}
//application.properties
logging.level.org.hibernate=debug
logging.level.org.orm.jdbc.bind=trace
REST CRUD API
REST
MIME Content Type
- The message format is described by MIME content type
- Multipurpose Internet Mail-Extension
- Basic Syntax: type / sub-type
- Examples
- text/html, text/plain
- application/json, application/xml, …
Step 2: create custom student exception
- The custom student exception will used by our REST service
- In our code, if we can’t find student, then we’ll throw an exception
- Need to define a custom student exception class
- StudentNotFoundException
Step 4: Add exception handler method
- Define exception handler methods(s) with @ExceptionHandler annotation
- Exception handler will return a ResponseEntity
- ResponseEntity is a wrapper for the HTTP response object
- ResponseEntity provides fine-grained control to specify:
- HTTP status code, HTTP headers and Response body
Specialized Annotation for services
- @Service applied to service implementations
- Spring will automatically register the service implementation
- thanks to component-scanning
HATEOAS
- Spring data REST endpoints are HATEOAS compliant
- HATEOAS: Hypermedia as the engine of application state
- Hypermedia-driven sites provide information to access REST interfaces
- Think of it as meta-data for REST data
https://spring.io/understand/HATEOAS
Advanced Features
- Spring Data REST advanced feature
- Pagination, sorting and searching
- Extending and adding custom queries with JPQL
- Query Domain Specific Language (Query DSL)
https://spring.io/projects/spring-data-rest
spring.data.rest.base-path=/magic-api
Spring Security Model
- Spring Security defines a framework for security
- Implemented using Servlet filters in the background
- Two methods of securing an app : declarative and programmatic
Spring Security with servlet filters
- Servlet filters are used to pre-process / post-process web requests
- Servlet filters can route web requests based on security logic
- Spring provides a bulk of security functionality with servlet filters
Security concept
- Authentication
- Check user id and password with credential stored in app / db.
- Authorization
- Check to see if user has an authorized role
Declarative Security
- Define application’s security constrains in configuration
- All Java config: @Configuration
- Provides separation of concerns between application code and security
Programmatic security
- Spring security provides and API for custom application coding
- Provides greater customization for specific app requirements
To test this use postman and authorization → basic auth
Cross-site Request Forgery (CSRF)
- Spring security can protect agains CSRF attacks
- Embed additional authentication data / token into all HTML forms
- On subsequent request, web app will verify token before processing
- Primary use case is tradional web application (HTML forms ets…)
When to use CSRF Protection?
- The Spring security team recommends
- Use CSRF protection for any normal browser web requests
- Tradiotional web apps with HTML forms to add / modify data
- If you are building a REST API for non-browser clients
- you may want to disable CSRF protection
- In general, not required for stateless REST APIs
- That use POST, PUT, DELETE and / or PATCH
Customize Database Access with spring security
- Can also customize the table schemas
- useful if you have custom tables specific to your project / custom
- you will be responsible for developing the code to access the data
- JDBC, JPA / Hibernate etc …
Spring security team recommendation
- Spring security recommends using the popular bcrypt algorithm
- bcrypt
- performs one way encrypted hasing
- adds a random salt to the password for additional protection
- includes support to defeat brute force attacks
How to get a bcrypt password
you have a plain text password and you want to encrypt using bcrypt
- Option 1 : use a website utility to perform the encryption
- Option 2 : write java code to perform the encryption
For security schema customization
- Tell spring how to query your custom tables
- provide query to find user by user name
- provide query to find authorities / roles by user name
Spring MVC
Where to place thymeleaf template?
- In spring boot, your thymeleaf template files go in
- src/main/resoureces/templates
- For web apps, thymeleaf templates have a .html extension
View template (more)
- Other view template supported - Groovy, velocity, freemarker, etc…
Java’s standard bean validation API
- Java has a standard bean validation API
- Defines a metadata model and API for entity validation
- Spring boot and thymeleaf also support the bean validation API
http://www.beanvalidation.org
Spring MVC Security
- Spring security defines a framework for security
- Implemented using Servlet filters in the background
- 2 methods of securing an app: declarative and programmatic
Spring security with servlet filters
- servlet filters are used to pre process / post process web requests
- servlet filters can route web requests based on security logic
- spring provides a buld of security functionality with servlet filters
Security concepts
- Authentication - Check user id and password with credentials stored in app / db
- Authorization - check to see if user has an authorized role
Declarative security
- Define application’s security constrains in configuration
- All java config : @Configuration
- Provides separation of concerns between application code and security
Programmatic security
- Spring security provides an API for custom application coding
- Provides greater customization for specific app requirements
Different login methods
- HTTP basic authentication
- Default login form - spring security provides a default login form
- Custom login form - your own look and feel, HTML + CSS
Custom login
Why use context path?
- Allows us to dynamically reference context path of application
- helps to keep links relative to application context path
- If you change context path of app, then links will still work
- much better than hard-coding context path…
Error
Logout process
- When a logout is processed, by default spring security will…
- Invalidate user’s HTTP session and remove session cookies, etc
- Send user back to your login page
- append a logout parameter : ?logout
Customize database access with spring security
- Can also customize the table schemas
- Useful if you have custom tables specific to your project / custom
- You will be responsible for developing the code to access the data - JDBC, JPA / Hibernate etc …
For security schema customization
- Tell spring how to query your custom tables
- Provide query to find user by user name
- Provide query to find authorities / roles by user name
JPA / Hibernate Advanced Mappings
Advanced mapping
- In the database, you most likely will have
- Multiple tables
- relationships between tables
- Need to model this with hibernate
- One to one
- one to many, many to one
- many to many
Primary key and foreign key
- Primary key : identify a unique row in a table
- Foreign key:
- Link tables together
- a field in one table that refers to primary key in another table
More on foreign key
- Main purpose is to preserve relationship between tables - Referential integrity
- Prevents operation that would destroy relationship
- Ensure only valid data is inserted into the foreign key column
- can only contain valid reference to primary key in other table
More about lazy loading
- When you lazy load, the data is only retrieved on demand
- however, this requires an open hibernate session
- need an connection to database to retrieve data
- If the hibernate session is closed
- and you attempt to retrieve lazy data
- hibernate will throw an exception
Aspect-Oriented Programming (AOP)
Other possible solutions?
- Inheritance?
- Every class would need to inherit from a base class
- can all classes extends from your base class? … plus no multiple inheritance
- Delegation?
- Classes would delegate loggin, security calls
- Still would need to update classes if we wanted to
- add / remove loggin or security
- add new feature like auditing, api management, instrumentation
Benefits of AOP
- Code for aspect is defined in a single class
- Much better than being scattered everywhere
- Promotes code reuse and easier to change
- Business code in your application is cleaner
- Only applies to business functionalty: AddAccount
- Reduce code complexity
- Configurable
- Based on configuration, apply aspects selectively to different parts of app
- No need to make changes to main application code … very important
- Most common
- logging, security, transactions
- Audit logging
- who, what, when, where
- Exception handling
- log exception and notify DevOps team via SMS / email
- Api management
- how many times has a method been called user
- analytics what are peak times? what is average load? who is top user?
Spring AOP Support
Aop terminology
- aspect : module of code for a cross-cutting concern (loggin, security, …)
- Advice: what action is taken and when it should be applied
- Join Point: when to apply code during program execution
- Pointcut : a predicate expression for where advice should be applied
Advice Types
- Before advice : run before the method
- After finally advice : run after the method (finally)
- After returning advice: run after the method (success execution)
- After throwing advice: run after method (if exception thrown)
- Around advice: run before and after method
Weaving
- Connecting aspects to target obejects to create an adviced object
- Different types of weaving - compile time, load time or run time
- Regarding performance : run time weaving is the slowest
AspectJ
- Original AOP framework, release in 2001 - www.eclipse.org/aspectj
- provides complete support for AOP
- Rich support for
- join points : method-level, constructor, field
- code weaving : compile-time, post compile time and load time
Comparing spring aop and aspectj
- Spring AOP only supports - method level join points, runtime code weaving (slower than aspectJ)
- AspectJ supports - join points : method-level, constructor, field. weaving : compilte time, post compile-time and load-time
- Spring AOP is a light implementation of AOP
- Solves common problems in enterprise applications
- My recommendation - start with spring AOP … easy to get started with, if you have complex requirement then move to AspectJ
@Before advice
@AfterThrowing Advice - use cases
- Log the exception
- Perform auditing on the exception
- Notify Devops team via email or SMS
- Encapsulate this functionality in AOP aspect for easy reuse
Exception propagation
- If you want to stop the exception propagation, then use the @Around advice, covered in later videos
@After Advice - use case
- Log the exception and / or perform auditing
- code to run regardless of method outcome
- encapsulate this functionality in AOP aspect for easy reuse
@After advice tips
- The @ After advice does not have access to the exception
- If you need exception, then @AfterThrowing advice
- The @After advice should be able to run in the case of success or error
- Your code should not depend on happy path or an exception
- Logging / auditing is the easiest case here
@Around advice - use case
- Most common : logging, auditing, security
- Pre processing and post processing data
- Instrumentation / profiling code
- How long does it take for a section of code to run?
- Managing exceptions
- Swallow / handle / stop exceptions