Dependency injection decouples code by injecting dependencies through interfaces rather than instantiating dependencies directly. This improves modularity, testability and replaceability. Aspect oriented programming further decouples cross-cutting concerns from the main code by injecting additional functionality at specific join points using pointcuts and advice. Examples show logging, caching, security and translation concerns injected as aspects into classes using annotations to specify join points.
8. public class WoosterAlone {
private RedAstonMartin theCar;
public WoosterAlone(){
theCar = new RedAstonMartin();
}
public void trip(){
theCar.drive();
}
}
9. public class WoosterWithGarage {
private Garage garage;
public WoosterWithGarage(Garage garage){
this.garage = garage;
}
public void trip(){
garage.claimCar("Best Car").drive();
}
}
10. public class WoosterAssisted {
private Car theCar;
public WoosterAssisted(Car theCar){
this.theCar = theCar;
}
public void trip(){
theCar.drive();
}
}
11. Why is the better?
• Decouples your code
• Reduces/Removes glue
• Large number of occasions where Wooster
needs the car
• Red Aston Martin in the shop – Black Jaguar
instead
• Roads are icy – take all weather car instead
12. Decoupling code
• Objects should only be responsible for
themselves (Single Responsibility Principle)
• Design to interfaces
• Modularity
– Easy to debug
– Easy to test
– Easy to replace
– Easy to iterate
13. Glue
• The code that joins your objects together
• Gluing should not be part of an object’s
responsibilities
• All other things being equal, the less amount
of glue, the better
15. Dependency Injection process
• Register your objects (“beans”)
– System determines dependencies
• Wire in dependencies
• Instantiate your beans
16. Dependencies
• Property setter to interface
– Can use constructor, but won’t get into that
• Wiring
– Wired explicitly during bean registry
– Pulled from other bean/properties
– Autowired
• By name
• By type
– Controlled Autowiring
20. Annotation Autowiring
public class WoosterAssisted {
@Autowired
private Car theCar;
private void setTheCar(Car theCar){
this.theCar = theCar;
}
public WoosterAssisted(){
}
public void trip(){
theCar.drive();
}
}
21. Annotation Autowiring by Name
public class WoosterAssisted {
@Resource(name=“RedLightning”)
private Car theCar;
private void setTheCar(Car theCar){
this.theCar = theCar;
}
public WoosterAssisted(){
}
public void trip(){
theCar.drive();
}
}
24. Environment sets
• Can set beans based on environment
• e.g.
– Local environment -> embedded database
– Testing -> Mocked data connection
– Dev environment -> dev SQL Server
– Dev + NoSQL -> dev Cassandra Server
– Prod -> prod SQL Server
25. Bean scopes
• Singleton (default)
• Prototype (new instance every time)
• Request (new instance every request)
• Session (new instance every session)
• Thread (new instance every thread)
26. Basic Messaging
public class BasicHelloMain {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
27. Separate Pieces of Functionality
• Message content
• Message renderer
• Connecting content to renderer
29. Separate Messaging
public class StandardOutMessageRenderer {
private SimpleMessageProvider provider;
public StandardOutMessageRenderer(){
setMessageProvider(new SimpleMessageProvider());
}
public void setMessageProvider(SimpleMessageProvider provider) {
this.provider = provider;
}
public SimpleMessageProvider getMessageProvider() {
return provider;
}
public void render() {
System.out.println(getMessageProvider().getMessage());
}
}
30. Separate Messaging
public class HelloWorldMain {
public static void main(String[] args) {
StandardOutMessageRenderer renderer = new StandardOutMessageRenderer();
renderer.render();
}
}
31. Central Managed
public interface MessageProvider {
public String getMessage();
}
public interface MessageRenderer {
public void render();
public void setMessageProvider(MessageProvider provider);
public MessageProvider getMessageProvider();
}
32. Central Managed
public class SimpleMessageProvider implements MessageProvider {
public String getMessage() {
return "Hello World!";
}
}
public class RegistryMessageProvider implements MessageProvider {
public String getMessage() {
return registry.lookup(“message.greeting");
}
}
33. Central Managed
public class StandardOutMessageRenderer implements MessageRenderer {
private MessageProvider provider;
public void setMessageProvider(MessageProvider provider) {
this.provider = provider;
}
public MessageProvider getMessageProvider() {
return provider;
}
public void render() {
if (getMessageProvider()==null){
throw new RuntimeException("Missing MessageProvider");
}
System.out.println(getMessageProvider().getMessage());
}
}
34. Central Managed
public class HelloWorldMain {
public static void main(String[] args) {
MessageProvider provider = new SimpleMessageProvider();
MessageProvider provider = new RegistryMessageProvider();
MessageRenderer renderer = new StandardOutMessageRenderer();
renderer.setMessageProvider(provider);
renderer.render();
}
}
42. Dependency Injection - injects registered
dependency objects into established Interface
properties
Aspect Oriented Programming - injects entirely
new functionality
43. What is not a dependency?
Functionality included in the flow of a request
that is not part of the central purpose of the
current object.
Good example of this is cross cutting concerns,
such as logging or security
45. Wooster wants to
• Keep track of all the things he does, for his
autobiography
• Keep track of the lies he tells his Aunt Agatha
• Keep his financial accounts in order
• Not intrude where he is not wanted
• Speak to foreign chaps without having to learn
their lingo
46. This involves
• Keep track of all the things he does, for his
autobiography - Logging
• Keep track of the lies he tells his Aunt Agatha -
Caching
• Keep his financial accounts in order -
Transactions
• Not intrude where he is not wanted - Security
• Speak to foreign chaps without having to learn
their lingo -Translation
47. @Logged
public class WoosterActions {
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
...
}
@Transactional
public void transferMoney(int amount, Account accountFrom, Account accountTo){
...
}
public enterClub(@Secured(“Wooster Approved”) Club club){
...
}
@Translate
public void talkTo(String message, Person listener){
...
}
@Translate
public String listenTo(Person talker){
...
}
}
48. Aspect components
• Join Point – a place in code that can be the
target for an aspect
• Point Cut – The query that selects the join
points that will the be targets for the aspect
• Advice – The code that will be run at the
selected Join Points
49. Join Point, Point Cuts, WTH???
• Very much like CSS/jQuery selectors
• A Join Point is anywhere that can be joined
– In selectors, this is any DOM element
• Selectors match on things like DOM hierarchy,
element type, id, attributes, etc.
• Point cuts match on things like Class, Package,
or Method names, Method signature,
Annotations, etc.
50. Why is there a formal name for Join
Points?
• Join points give us access to the runtime
values when advice is being run
– Current class
– Method name
– Argument names and values
– Annotations
– etc.
51. AspectJ Point Cut syntax
<match type>(<access> <return type>
<class>.<method>(<method parameters>))
e.g.
– execution(public String Wooster.*(..))
– execution(* @Logging*.*(..))
Don’t focus on this. I’m using fake syntax in my
examples.
58. Inter Type Definitions (ITD)
• Adds code at compile time to matching Join
Points
• Enables the Mixin behavior of many advices
• Can set up a dependency injection
59. @Logged
public class WoosterActions {
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
lieGeneratingCode(situation, occurrence);
}
@Transactional
public void transferMoney(int amount, Account accountFrom, Account accountTo){
transferFromAccount(accountFrom, amount);
transferToAccount(accountTo, amount);
}
public enterClub(@Secured(“Wooster Approved”) Club club){
enterClubCode(club);
}
@TranslateIncoming
public void talkTo(String message, Person listener){
talkToCode(message, listener);
}
@TranslateReturn
public String listenTo(Person talker){
return listenToCode(talker);
}
}
60. Logging Aspect
@Aspect
public class LoggingAspect {
private Log4JLogger log = new Log4JLogger("Jeeves");
@Before("@within(Logging) && execution(public * *.*(..)")
public void logExecution(JoinPoint joinPoint){
log.info(joinPoint.getSignature().toString());
}
}
61. Caching Aspect
@Aspect
public class CachingAspect {
@Autowired
private Cache cache;
@Around("@annotation(Cacheable)")
public Object checkCache(ProceedingJoinPoint joinPoint) throws Throwable{
Object result = cache.get(joinPoint.getTarget().hashCode());
if (result != null){
return result;
}
result = joinPoint.proceed();
cache.put(joinPoint.getTarget().hashCode(), result);
return result;
}
}
62. Generate Lies
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
return lieGeneratingCode(situation, occurrence);
}
63. Add Logging Aspect
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
log.info(joinPoint.getSignature().toString());
return lieGeneratingCode();
}
64. Add Cached Aspect
@Cached
public String generateLieForAuntAgatha(String situation, Date occurrence){
log.info(joinPoint.getSignature().toString());
Object result = cache.get(joinPoint.getTarget().hashCode());
if (result != null){
return result;
}
result = lieGeneratingCode();
cache.put(joinPoint.getTarget().hashCode(), result);
return result;
}
65. Transactional Aspect
@Aspect
public class TransactionalAspect {
@Autowired
private TransactionService transactionService;
@Around("@annotation(Transactional)")
public Object doTransaction(ProceedingJoinPoint joinPoint){
transactionService.startTransaction();
try{
Object result = joinPoint.proceed();
transactionService.commitTransaction();
return result;
} catch (Throwable e) {
transactionService.rollbackTransaction();
throw e;
}
}
}