Spring Architecture Series-9.Understanding Design Patterns Through Spring Framework Implementation




Introduction
Design pattern are reusable solutions to common soft ware design problems.The Spring Framework is a perfect example of how design patterns can be effectively applied to create a robust and flexible application framework. In this article,I'll explore the key design patterns used...

? https://www.roastdev.com/post/....spring-architecture-

#news #tech #development

Favicon 
www.roastdev.com

Spring Architecture Series-9.Understanding Design Patterns Through Spring Framework Implementation

Introduction
Design pattern are reusable solutions to common soft ware design problems.The Spring Framework is a perfect example of how design patterns can be effectively applied to create a robust and flexible application framework. In this article,I'll explore the key design patterns used in my miniSpring implementation.


Core Design Patterns



1. Factory Pattern
The Factory Pattern is central to Spring's IoC container:
⛶public interface BeanFactory {
Object getBean(String beanName) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name);
boolean isPrototype(String name);
Class getType(String name);
}Implementation example
⛶public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory {
protected MapString, BeanDefinition beanDefinitionMap =
new ConcurrentHashMap(256);

@Override
public Object getBean(String beanName) throws BeansException {
Object singleton = getSingleton(beanName);
if (singleton == null) {
singleton = createBean(beanName);
}
return singleton;
}
}Kay aspects:
Object creation abstraction
Dependency management
Lifecycle control



2. Proxy Pattern
The Proxy Pattern is used extensively in Spring's AOP implementation:
⛶public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private Object target;
private PointcutAdvisor advisor;

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (this.advisor.getPointcut().getMethodMatcher()
.matches(method, target.getClass())) {
MethodInterceptor interceptor = advisor.getMethodInterceptor();
MethodInvocation invocation = new ReflectiveMethodInvocation(
proxy, target, method, args, target.getClass());
return interceptor.invoke(invocation);
}
return method.invoke(target, args);
}
}Features:
Dynamic proxy creation
Method interception
Advice application



3. Observer Pattern
The Observer Pattern is implemented in Spring's event mechanism:
⛶public interface ApplicationListenerE extends ApplicationEvent
extends EventListener {
void onApplicationEvent(E event);
}

public class SimpleApplicationEventPublisher
implements ApplicationEventPublisher {
private ListApplicationListener listeners = new ArrayList();

@Override
public void publishEvent(ApplicationEvent event) {
for (ApplicationListener listener : listeners) {
listener.onApplicationEvent(event);
}
}
}Key aspects:
Event publishing
Listener registration
Event handling



4. Template Method Pattern
The Template Method Pattern is used in JDBC operation:
⛶public class JdbcTemplate {
public Object query(String sql, Object[] args,
PreparedStatementCallBack pstmtCallBack) {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
ArgumentPreparedStatementSetter setter =
new ArgumentPreparedStatementSetter(args);
setter.setValues(pstmt);
return pstmtCallBack.doInPreparedStatement(pstmt);
} finally {
// Resource cleanup
}
}
}Features:
Algorithm skeleton
Customizable steps
Resource management



5. Strategy Pattern
The Strategy Pattern is used in various parts of Spring:
⛶public interface Pointcut {
MethodMatcher getMethodMatcher();
}

public class NameMatchMethodPointcut implements Pointcut {
private String mappedName = "";

@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class targetClass) {
return mappedName.equals(method.getName());
}
};
}
}Key aspects:
Algorithm selection
Runtime configuration
Extensibility
## Pattern Integration
### 1. Factory and Proxy Integration

⛶public class ProxyFactoryBean implements FactoryBeanObject {
private Object target;
private PointcutAdvisor advisor;

@Override
public Object getObject() throws Exception {
return createAopProxy().getProxy();
}

protected AopProxy createAopProxy() {
return getAopProxyFactory().createAopProxy(target, this.advisor);
}
}


2. Observer and Template Method Integration
⛶public abstract class AbstractApplicationContext
implements ApplicationContext {
private ApplicationEventPublisher applicationEventPublisher;

public void refresh() throws BeansException {
// Template method steps
initApplicationEventPublisher();
registerListeners();
finishRefresh();
}

protected void finishRefresh() {
// Observer pattern usage
publishEvent(new ContextRefreshedEvent(this));
}
}


Design Pattern Benefits



1. Flexibility

Easy to extend
Loose coupling
Runtime configuration
### 2. Maintainability
Clear structure
Separation of concerns
Reusable components
### 3. Scalability
Modular design
Efficient resource management
Performance optimization



Best Practices



1. Pattern Selection

Match pattern to problem
Consider trade-offs
Avoid over-engineering
### 2. Implementation
Clean interfaces
Proper abstraction
Error handling
### 3. Integration
Pattern combination
Resource management
Performance consideration



Common Challenges and Solutions

Complexity Management


Clear hierarchy
Interface segregation
Documentation


Performance


Caching strategies
Resource pooling
Lazy initialization


Extensibility


Extension points
Plugin architecture
Custom implementations





Conclusion
Understanding design patterns through Spring implementation provides:
Deep insight into pattern usage
Practical application examples
Best practice guidelines
Problem-solving strategies
Key takeaways:
Pattern selection criteria
Implementation techniques
Integration approaches
Performance considerations
This implementation demonstrates how design patterns can be effectively combined to create a robust and flexible framework.

Similar Posts

Similar

Spring Architecture Series-8.Implementing Event Publishing and Listening Mechanism




Introduction
Event-driven programming is a powerful paradigm that enables loose coupling between components in an application. In this article, I'll explore how to implement an event publishing and listening mechanism in a Spring-like framework, based on my miniSpring project's implementati...

? https://www.roastdev.com/post/....spring-architecture-

#news #tech #development

Favicon 
www.roastdev.com

Spring Architecture Series-8.Implementing Event Publishing and Listening Mechanism

Introduction
Event-driven programming is a powerful paradigm that enables loose coupling between components in an application. In this article, I'll explore how to implement an event publishing and listening mechanism in a Spring-like framework, based on my miniSpring project's implementation.


Core Components
The event mechanism implementation consists of several key components:
⛶src/com/yaruyng/context/
├── ApplicationEvent.java
├── ApplicationListener.java
├── ApplicationEventPublisher.java
├── SimpleApplicationEventPublisher.java
├── ApplicationContextEvent.java
├── ContextRefreshEvent.java
└── ContextRefreshedEvent.java


Event Base Class
The ApplicationEvent class serves as the base for all application events:
⛶public class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 1L;
protected String msg = null;

public ApplicationEvent(Object source) {
super(source);
this.msg = source.toString();
}
}Key features:
Extends EventObject from Java standard library
Serializable support
Source object tracking
Message support



Event Listener Interface
The ApplicationListener interface defines the contract for event listeners:
⛶public interface ApplicationListenerE extends ApplicationEvent extends EventListener {
void onApplicationEvent(E event);
}Features:
Generic type support
Single responsibility principle
Clear event handling contract



Event Publisher
The SimpleApplicationEventPublisher implements the event publishing mechanism:
⛶public class SimpleApplicationEventPublisher implements ApplicationEventPublisher {
ListApplicationListener listeners = new ArrayList();

@Override
public void publishEvent(ApplicationEvent event) {
for (ApplicationListener listener : listeners) {
listener.onApplicationEvent(event);
}
}

@Override
public void addApplicationListener(ApplicationListener listener) {
this.listeners.add(listener);
}
}Key aspects:
Listener management
Event broadcasting
Synchronous event processing



Context Events



1. Context Refresh Event
⛶public class ContextRefreshEvent extends ApplicationContextEvent {
public ContextRefreshEvent(ApplicationContext source) {
super(source);
}
}


2. Context Refreshed Event
⛶public class ContextRefreshedEvent extends ApplicationContextEvent {
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}


Integration with Application Context
The AbstractApplicationContext integrates event support:
⛶public abstract class AbstractApplicationContext implements ApplicationContext {
private ApplicationEventPublisher applicationEventPublisher;

public abstract void registerListeners();
public abstract void initApplicationEventPublisher();

public void refresh() throws BeansException, IllegalStateException {
// Initialize event publisher
initApplicationEventPublisher();

// Register listeners
registerListeners();

// Other initialization steps...

// Publish refresh event
finishRefresh();
}

public void finishRefresh() {
publishEvent(new ContextRefreshedEvent(this));
}
}


Event Processing Flow



1. Event Register
⛶public void registerListeners() {
String[] beanDefinitionNames = this.getBeanFactory().getBeanDefinitionNames();
for (String bdName : beanDefinitionNames) {
Object bean = getBean(bdName);
if(bean instanceof ApplicationListener) {
this.getApplicationEventPublisher()
.addApplicationListener((ApplicationListener) bean);
}
}
}


2. Event Publishing
⛶public void publishEvent(ApplicationEvent event) {
this.getApplicationEventPublisher().publishEvent(event);
}


Usage Example



1. Creating Custom Events
⛶public class UserRegisteredEvent extends ApplicationEvent {
private final User user;

public UserRegisteredEvent(Object source, User user) {
super(source);
this.user = user;
}

public User getUser() {
return user;
}
}


2. Implementing Event Listeners
⛶@Component
public class EmailNotificationListener implements ApplicationListenerUserRegisteredEvent {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
User user = event.getUser();
// Send welcome email
sendWelcomeEmail(user);
}
}


3. Publishing Event
⛶@Service
public class UserService {
@Autowired
private ApplicationEventPublisher eventPublisher;

public void registerUser(User user) {
// Save user
userRepository.save(user);

// Publish event
eventPublisher.publishEvent(new UserRegisteredEvent(this, user));
}
}


Key Features



1.Event Types

Context events
Custom events
Event hierarchy
### 2. Listener Management
Dynamic registration
Type-safe handling
Multiple listeners
### 3. Event Publishing
Synchronous processing
Error handling
Event ordering



Best Practice

Event Design


Clear event hierarchy
Immutable event data
Meaningful event names


Listener Implementation


Single responsibility
Error handling
Performance consideration


Event Publishing


Appropriate timing
Error propagation
Transaction boundaries





Common Challenges and Solutions

Event Ordering


Listener priority
Synchronous processing
Event queuing


Error Handling


Exception propagation
Listener isolation
Recovery mechanisms


Performance


Asynchronous processing
Event filtering
Listener optimization





Conclusion
Implementing an event mechanism provides:
Loose coupling between components
Asynchronous communication
Extensible architecture
Decoupled business logic
Key takeaways:
Understanding event-driven architecture
Event listener patterns
Event publishing mechanisms
Integration with IoC container
This implementation demonstrates how to create a robust event system while maintaining simplicity and flexibility.
Similar

Trustless Bitcoin Swaps with DID, Nostr, and HTLCs




? The Problem
Say Alice wants to send 100,000 sats to Bob.But:
Alice only has on-chain Bitcoin.
Bob only uses the Lightning Network.
They want to swap — but without using a centralized exchange or trusted custodian.
Can they do it trustlessly?Yes — with:

DIDs (Decentralized Identifi...

? https://www.roastdev.com/post/....trustless-bitcoin-sw

#news #tech #development

Favicon 
www.roastdev.com

Trustless Bitcoin Swaps with DID, Nostr, and HTLCs

? The Problem
Say Alice wants to send 100,000 sats to Bob.But:
Alice only has on-chain Bitcoin.
Bob only uses the Lightning Network.
They want to swap — but without using a centralized exchange or trusted custodian.
Can they do it trustlessly?Yes — with:

DIDs (Decentralized Identifiers)

Nostr (a decentralized messaging protocol)
Bitcoin + Lightning

HTLCs (Hashed Time-Locked Contracts)



? A Simple Use Case
Let’s walk through a real-world example that almost anyone can understand:


? Scenario: On-chain to Lightning Swap


Alice wants to pay 100k sats on-chain.

Bob wants to receive 100k sats on Lightning.
They don’t trust each other and want to swap trustlessly.



? Enter DID + Nostr + HTLCs



✅ 1. Identity via DIDs on Nostr

Both Alice and Bob have DIDs tied to their Nostr pubkeys.
DIDs make it possible to verify identities and sign messages.
Alice posts a signed message to Nostr offering the swap.

⛶{
"type": "swap-offer",
"from": "did:nostr:pubkeyalice",
"to": "any",
"amount": 100000,
"direction": "onchain-to-lightning",
"hashlock": "abcdef123456...",
"expires_in": 3600
}Bob sees it and replies with a signed acceptance.


? 2. Coordinating via Nostr

The offer and acceptance are broadcast as ephemeral Nostr events.
Both parties agree on:


The amount
The hashlock
Timeouts
Where to send funds





No servers, no intermediaries — just pubkey-signed messages over a decentralized relay network.


? 3. The HTLC Swap
They now execute the swap using the same secret hash:


Alice (on-chain):

Sends 100k sats to a Bitcoin HTLC (can only be claimed with the secret before timeout).



Bob (Lightning):

Sends 100k sats to a Lightning HTLC (also locked with the same hash).
As soon as one party claims the funds, the preimage is revealed, and the other can claim theirs too.


✅ 4. Atomic Swap Complete

Bob claims the on-chain BTC → reveals the secret.
Alice uses the same secret to claim her Lightning BTC.

No one can cheat — it’s enforced by the HTLCs and timeouts.



✨ Why This Matters
This setup gives us:✅ Trustless swaps
✅ No custodians or centralized services
✅ Cross-layer interoperability
✅ Identity-based coordination via Nostr DIDsAnd it all works with:
Bitcoin
Lightning
DID documents
Open message relays



? What’s Next?

Add wallet support for DID-authenticated swap offers over Nostr.
Explore multi-party or ring swaps.



? TL;DR

DID + Nostr + HTLCs = trustless swaps across Bitcoin and Lightning, with identity and coordination baked in.
No middleman. Just keys, hashes, and the open web.
Similar

Spring Architecture Series-7.Implementing Annotation-Driven Development Support




Introduction
Annotation-driven development has revolutionized Java development by providing a declarative way to configure and manage application components. In this article, I'll explore how to implement annotation support in a Spring-like framework, based on my miniSpring project's implem...

? https://www.roastdev.com/post/....spring-architecture-

#news #tech #development

Favicon 
www.roastdev.com

Spring Architecture Series-7.Implementing Annotation-Driven Development Support

Introduction
Annotation-driven development has revolutionized Java development by providing a declarative way to configure and manage application components. In this article, I'll explore how to implement annotation support in a Spring-like framework, based on my miniSpring project's implementation.


Core Components
The annotation support implementation consists of several key components:
⛶src/com/yaruyng/
├── beans/factory/annotation/
│ ├── AutowiredAnnotationBeanPostProcessor.java
│ └── Autowired.java
└── web/
├── RequestMapping.java
└── method/


Annotation Processing Infrastructure



1. The Autowired Annotation
The @Autowired annotation is the foundation for dependency injection:
⛶@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}Key features:
Field-level annotation
Runtime retention
Simple and focused purpose



2. The AutowiredAnnotationBeanPostProcessor
The processor handle @Autowired annotation processing
⛶public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private BeanFactory beanFactory;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
Object result = bean;
Class clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();

if(fields != null) {
for (Field field : fields) {
boolean isAutowired = field.isAnnotationPresent(Autowired.class);
if(isAutowired) {
String fieldName = field.getName();
Object autowiredObj = this.getBeanFactory().getBean(fieldName);
try {
field.setAccessible(true);
field.set(bean, autowiredObj);
System.out.println("autowire " + fieldName + " for bean " + beanName);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
return result;
}
}Features:
Field-level dependency injection
Reflection-based processing
Integration with bean lifecycle



Web Annotations



1. RequestMapping Annotation
The @RequestMapping annotation handles URL mapping:
⛶@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
}Usage example
⛶@Controller
public class UserController {
@RequestMapping("/users")
public ListUser getUsers() {
// Implementation
}
}


Annotation Processing Flow



1.Bean Post-Processing
The annotation processing happens during bean initialization:
⛶public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 1. Get bean class
Class clazz = bean.getClass();

// 2. Get declared fields
Field[] fields = clazz.getDeclaredFields();

// 3. Process each field
for (Field field : fields) {
// 4. Check for annotations
if (field.isAnnotationPresent(Autowired.class)) {
// 5. Get dependency
Object dependency = getBeanFactory().getBean(field.getName());

// 6. Inject dependency
field.setAccessible(true);
field.set(bean, dependency);
}
}

return bean;
}


2.Request Mapping Processing
The request mapping processing happens during request handling:
⛶protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception {
// 1. Get handler method
HandlerMethod handlerMethod = handlerMapping.getHandler(request);

// 2. Execute handler
ModelAndView mv = handlerAdapter.handle(request, response, handlerMethod);

// 3. Render view
render(request, response, mv);
}


Implementation Details



1.Field Injection
⛶private void injectDependency(Field field, Object bean, String beanName) {
try {
// 1. Get dependency name
String fieldName = field.getName();

// 2. Get dependency from container
Object dependency = getBeanFactory().getBean(fieldName);

// 3. Make field accessible
field.setAccessible(true);

// 4. Set dependency
field.set(bean, dependency);

System.out.println("autowire " + fieldName + " for bean " + beanName);
} catch (Exception e) {
e.printStackTrace();
}
}


2. Request Mapping Resolution
⛶public HandlerMethod getHandler(HttpServletRequest request) {
String requestURI = request.getRequestURI();
String method = request.getMethod();

// Find matching handler method
for (HandlerMethod handler : handlerMethods) {
RequestMapping mapping = handler.getMethodAnnotation(RequestMapping.class);
if (mapping != null mapping.value().equals(requestURI)) {
return handler;
}
}

return null;
}


Usage Example



1.Dependency Injection
⛶@Service
public class UserService {
@Autowired
private UserRepository userRepository;

@Autowired
private EmailService emailService;

public void createUser(User user) {
userRepository.save(user);
emailService.sendWelcomeEmail(user);
}
}


2.Request Mapping
⛶@Controller
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;

@RequestMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}


Key Features



1.Dependency Injection

Field-level injection
Constructor injection support
Circular dependency handling
### 2.Request Mapping
URL pattern matching
HTTP method support
Path variable handling
### 3. Annotation Processing
Runtime processing
Reflection-based implementation
Extensible design



Best Practices



1.Annotation Design

Clear and focused purpose
Runtime retention when needed
Proper target specification
### 2.Processing Implementation
Efficient reflection usage
Proper exception handling
Resource cleanup
### 3.Integration
Clean integration with IoC
Proper lifecycle management
Performance optimization



Common Challenges and Solutions



1.Circular Dependencies

Lazy initialization
Constructor injection
Dependency resolution
### 2.Performance
Annotation caching
Reflection optimization
Resource management
### 3.Error Handling
Clear error messages
Proper exception propagation
Recovery mechanisms



Conclusion
Implementing annotation support provides:
Declarative configuration
Clean and maintainable code
Flexible dependency management
Simplified request handling
Key takeaways:
Understanding annotation processing
Dependency injection patterns
Request mapping mechanisms
Performance optimization techniques
This implementation demonstrates how to create a robust annotation-driven framework while maintaining simplicity and flexibility.